读取大文本文件,内存不足异常

时间:2012-11-16 11:43:12

标签: c# .net exception .net-4.0 out-of-memory

我想读大TXT文件大小是500 MB, 首先我使用

var file = new StreamReader(_filePath).ReadToEnd();  
var lines = file.Split(new[] { '\n' });

但它丢失了内存Exception然后我尝试逐行读取但是在读取大约150万行后再次抛出内存异常

  using (StreamReader r = new StreamReader(_filePath))
         {            
             while ((line = r.ReadLine()) != null)            
                 _lines.Add(line);            
         }

或者我用过

  foreach (var l in File.ReadLines(_filePath))
            {
                _lines.Add(l);
            }

但我又收到了

  

发生了'System.OutOfMemoryException'类型的异常   mscorlib.dll但未在用户代码中处理

我的机器是功能强大的机器,配有8GB内存,因此它不应该是我的机器问题。

p.s:我试图在NotePadd ++中打开这个文件,我收到'文件太大而无法打开'例外。

5 个答案:

答案 0 :(得分:33)

只需使用File.ReadLines即可返回IEnumerable<string>并且不会一次性将所有行加载到内存中。

foreach (var line in File.ReadLines(_filePath))
{
    //Don't put "line" into a list or collection.
    //Just make your processing on it.
}

答案 1 :(得分:4)

异常的原因似乎是_lines集合的增长,但没有阅读大文件。你正在读行和adding to some collection _lines which will be taking memory and causing out of memory execption。您可以应用过滤器仅将所需的行放到_lines集合中。

答案 2 :(得分:1)

编辑:

将整个文件加载到内存中会导致对象增长,如果无法为对象分配足够的连续内存,.net将抛出OOM异常。

答案仍然是一样的,你需要流式传输文件,而不是读取整个内容。这可能需要重新构建您的应用程序,但是使用IEnumerable<>方法可以在应用程序的不同区域堆叠业务流程并推迟处理。


具有8GB RAM的“强大”机器无法在内存中存储500GB文件,因为500大于8(另外,由于操作系统将保留一些,因此不会得到8 ,你不能在.Net中分配所有内存,32位有2GB限制,打开文件并存储该行将保存数据两次,有一个对象大小开销....)

您无法将整个内容加载到内存中进行处理,您必须通过处理流式传输文件。

答案 3 :(得分:1)

我知道这是一篇旧帖子,但 Google 于 2021 年将我发送到这里..

只是为了强调以上 igrimpe 的评论:

我最近在 StreamReader.ReadLine() 上遇到了一个 OutOfMemoryException 异常,它在巨大的文本文件文件夹中循环。

正如 igrimpe 所提到的,您有时会遇到这种情况,即您的输入文件在换行符方面表现出缺乏一致性。如果您在遍历文本文件时遇到这种情况,请仔细检查您的输入文件中是否有意外字符/ascii 编码的十六进制或二进制字符串等。

就我而言,我将 60 gb 有问题的文件拆分为 256mb 的块,让我的文件迭代器将有问题的文本文件作为异常陷阱的一部分存储起来,然后通过删除有问题的行来修复有问题的文本文件。

答案 4 :(得分:0)

您必须先数行。 它的速度较慢,但​​您最多可以读取2,147,483,647行。

int intNoOfLines = 0;
using (StreamReader oReader = new 
StreamReader(MyFilePath))
{
    while (oReader.ReadLine() != null) intNoOfLines++;
}
string[] strArrLines = new string[intNoOfLines];
int intIndex = 0;
using (StreamReader oReader = new 
StreamReader(MyFilePath))
{
    string strLine;
    while ((strLine = oReader.ReadLine()) != null)
    {
       strArrLines[intIndex++] = strLine;
    }
}