对于120 MB CSV文件的String.Split()的.NET System.OutOfMemoryException

Cra*_*g W 6 .net csv split out-of-memory

我正在使用C#读取~120 MB纯文本CSV文件.最初我通过逐行读取来进行解析,但最近确定首先将整个文件内容读入内存的速度要快几倍.解析已经非常慢了,因为CSV在引号中嵌入了逗号,这意味着我必须使用正则表达式拆分.这是我发现的唯一可靠的工作方式:

string[] fields = Regex.Split(line, 
@",(?!(?<=(?:^|,)\s*\x22(?:[^\x22]|\x22\x22|\\\x22)*,)
(?:[^\x22]|\x22\x22|\\\x22)*\x22\s*(?:,|$))");
// from http://regexlib.com/REDetails.aspx?regexp_id=621
Run Code Online (Sandbox Code Playgroud)

为了在将整个内容读入内存后进行解析,我在换行符上进行字符串拆分以获得包含每一行的数组.但是,当我在120 MB文件上执行此操作时,我得到了一个System.OutOfMemoryException.当我的计算机有4 GB RAM时,为什么内存耗尽?有没有更好的方法来快速解析复杂的CSV?

Jay*_*ggs 8

除非必须,否则不要滚动自己的解析器.我有幸运气这个:

快速CSV阅读器

如果没有别的东西,你可以看看引擎盖,看看别人怎么做.


Bri*_*sen 7

基本上任何大小的分配都可以获得OutOfMemoryException.当你分配一块内存时,你真的要求连续的内存满足所需的大小.如果无法兑现,您将看到OutOfMemoryException.

您还应该知道,除非您运行64位Windows,否则您的4 GB RAM将分为2 GB内核空间和2 GB用户空间,因此您的.NET应用程序无法访问超过2 GB的默认值.

在.NET中进行字符串操作时,由于.NET字符串是不可变的,因此存在创建大量临时字符串的风险.因此,您可能会看到内存使用率急剧上升.


Mik*_*nen 5

如果您将整个文件读入字符串,则应该使用StringReader.

StringReader reader = new StringReader(fileContents);
string line;
while ((line = reader.ReadLine()) != null) {
    // Process line
}
Run Code Online (Sandbox Code Playgroud)

这应该与从文件中流式传输相同,区别在于内容已经在内存中.

测试后编辑

尝试使用140MB文件进行上述处理,其中处理包括使用line.Length递增长度变量.这在我的电脑上花了大约1.6秒.在此之后我尝试了以下内容:

System.IO.StreamReader reader = new StreamReader("D:\\test.txt");
long length = 0;
string line;
while ((line = reader.ReadLine()) != null)
    length += line.Length;
Run Code Online (Sandbox Code Playgroud)

结果是大约1秒钟.

当然,您的里程可能会有所不同,特别是如果您正在从网络驱动器读取数据,或者您的处理需要足够长的时间才能让硬盘驱动器寻找其他地方 但是如果你使用FileStream来读取文件而你没有缓冲.StreamReader提供缓冲,大大增强了读取.