17

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

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

但它抛出了内存异常然后我尝试逐行读取,但是在读取了大约 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);
            }

但我又收到了

mscorlib.dll 中出现“System.OutOfMemoryException”类型的异常,但未在用户代码中处理

我的机器是具有 8GB 内存的强大机器,所以它不应该是我的机器问题。

ps:我尝试在 NotePadd++ 中打开此文件,但收到“文件太大无法打开”异常。

4

5 回答 5

38

只需使用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.
}
于 2012-11-16T12:02:00.643 回答
4

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

于 2012-11-16T11:45:11.350 回答
3

我知道这是一篇旧帖子,但谷歌在 2021 年把我送到了这里。

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

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

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

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

于 2021-07-30T15:43:29.560 回答
1

编辑:

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

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


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

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

于 2012-11-16T11:53:13.937 回答
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;
    }
}
于 2018-09-29T06:37:36.440 回答