我使用下面的代码来分割字符串,但这需要很多时间.
using (StreamReader srSegmentData = new StreamReader(fileNamePath)) { string strSegmentData = ""; string line = srSegmentData.ReadToEnd(); int startPos = 0; ArrayList alSegments = new ArrayList(); while (startPos < line.Length && (line.Length - startPos) >= segmentSize) { strSegmentData = strSegmentData + line.Substring(startPos, segmentSize) + Environment.NewLine; alSegments.Add(line.Substring(startPos, segmentSize) + Environment.NewLine); startPos = startPos + segmentSize; } }
请建议我另一种方法将字符串拆分为固定大小的较小块
首先,您应该定义块大小的含义.如果您的意思是具有固定数量的代码单元的块,那么您的实际算法可能会很慢,但它可以工作.如果它不是你想要的,你实际上是指具有固定数量字符的块,那么它就会被打破.我在这篇Code Review帖子中讨论了类似的问题:将一个字符串拆分成相同长度的块然后我将在这里仅重复相关部分.
您正在进行分区Char
但是String
是UTF-16编码,那么您可能会产生损坏的字符串,至少有三种情况:
一个字符使用多个代码单元进行编码.该字符的Unicode代码点被编码为两个UTF-16代码单元,每个代码单元最终可能位于两个不同的片中(并且两个字符串都将无效).
一个字符由多个代码点组成.您正在处理由两个单独的Unicode代码点(例如Han字符)创建的字符.
一个字符组合了字符或修饰符.这比您想象的更常见:例如Unicode组合字符,如U + 0300 COMBINING GRAVE ACCENT用于构建 à和Unicode 修饰符,如U + 02BC MODIFIER LETTER APOSTROPHE.
编程语言和人类的字符定义是完全不同的,例如在斯洛伐克语中dž是单个字符,但它是由2/3 Unicode代码点构成的,在这种情况下也是2/3 UTF-16代码单元"dž".Length > 1
.更多关于这和其他文化问题上我怎么能执行由字符比较一个Unicode字符知道?.
存在连接.假设一个连字是一个代码点(并且还假设它被编码为一个代码单元),那么您将它视为单个字形,但它代表两个字符.在这种情况下该怎么办?一般来说,字符的定义可能相当模糊,因为根据使用该单词的学科,它具有不同的含义.您不能(可能)正确处理所有内容,但您应该设置一些约束和文档代码行为.
一个提议(和未经测试)的实现可能是这样的:
public static IEnumerableSplit(this string value, int desiredLength) { var characters = StringInfo.GetTextElementEnumerator(value); while (characters.MoveNext()) yield return String.Concat(Take(characters, desiredLength)); } private static IEnumerable Take(TextElementEnumerator enumerator, int count) { for (int i = 0; i < count; ++i) { yield return (string)enumerator.Current; if (!enumerator.MoveNext()) yield break; } }
它没有针对速度进行优化(正如您所看到的那样,我尝试使用枚举来保持代码简短和清晰)但是,对于大文件,它仍然比您的实现更好(请参阅下一段的原因).
关于您的代码注意:
你正在建立一个巨大的ArrayList
(?!)来保持结果.另请注意,通过这种方式可以ArrayList
多次调整大小(即使给定输入大小和块大小,也可以知道其最终大小).
strSegmentData
重建多次,如果你需要累积必须使用的字符,StringBuilder
否则每个操作都会分配一个新字符串并复制旧值(它很慢,它也给垃圾收集器增加了压力).
有更快的实现(请参阅链接的Code Review帖子,尤其是Heslacher的更快版本的实现),如果您不需要正确处理Unicode(您确定只管理US ASCII字符),那么还有一个非常易读的实现来自Jon Skeet(请注意,在对代码进行分析之后,您仍可以提高其预分配正确大小输出列表的大文件的性能).我不在这里重复他们的代码然后请参考链接的帖子.
根据您的具体情况,您不需要在内存中读取整个大文件,您可以在时间读取/解析n个字符(不要过于担心磁盘访问,I/O是缓冲的).它会略微降低性能,但会大大提高内存使用率.或者,您可以逐行阅读(管理处理跨行块).