【问题标题】:File.ReadLines throws OutOfMemoryExceptionFile.ReadLines 抛出 OutOfMemoryException
【发布时间】:2015-02-28 01:22:57
【问题描述】:

我有一个奇怪的问题,我似乎找不到解决方案。 我正在尝试按 8M 行的块读取大文件(从 500Mb 到 2Gb)。

为此,我创建了以下内容:

public static List<string> read_file(string path, Int32 start, Int32 end, Boolean is_big_file)
{
    try
    {
        List<string> lines = new List<string>();

        if (is_big_file)
            lines = File.ReadLines(path).Skip(start).Take(end - start).ToList();
        else
            lines = File.ReadAllLines(path).ToList();

        return lines;
    }
    catch { return null; }
}

如果文件的行数少于 8M,则使用 ReadAllLines 并且一切正常。 如果文件不止于此,它将使用 ReadLines.Skip.Take。

第一个块有效,我收到前 8 M 行。 开始 = 0。结束 = 8,000,000。

第二个块不起作用。 开始 = 8,000,000。 end = 16,000,000 或文件的最后一行(取决于行数)。 出于某种原因,当我要读取的行数少于 8M(end = 12,500,000)时,我会收到 OutOfMemoryException。

你知道为什么会这样吗? Skip 是否也缓存原始行? 有没有更优雅的解决方案?

谢谢!

【问题讨论】:

  • 在每次调用读取任何后续块时,您实际上也在读取所有前面的行(块)。难怪它会疯狂地吞噬记忆。您应该使用 StreamReader 更好地处理文件。
  • 请问,调用者如何调用这个方法,对于一个大文件,读取多个批次?令我惊讶的是,虽然您的方法可能效率极低,但 File.ReadLines 返回一个 IEnumerable,它在内部使用 StreamReader(与下面接受的答案相同)读取一行时间......除非你明确地在内存中保存大量行,或者做其他错误,否则应该很难得到 OOM 异常(虽然并非不可能......而且,这种方法肯定是低效的)。跨度>
  • 如果您只是因为担心要处理一个大文件而实施批处理,并且您需要做的就是处理每一行一次,一次处理一行,我建议保持简单,只需使用ReadLines 方法返回的IEnumerable 迭代所有行。鉴于迭代器是如何使用StreamReader 实现的,不应加载所有行(无需重新如果我正确理解您的需求,请发明轮子)。见 - referencesource.microsoft.com/#mscorlib/system/io/…

标签: c# file


【解决方案1】:

实际上,使用这个:

File.ReadLines(path)

您正在阅读所有行。您最好使用FileStream 和Seek 来读取您要读取的字节。像这样的:

using (FileStream fs = new FileStream(path, FileMode.Open))
{
    fs.Seek(start, SeekOrigin.Begin);
    TextReader tr = new StreamReader(fs);

    string line = tr.ReadLine();
}

【讨论】:

    猜你喜欢
    • 2014-09-20
    • 1970-01-01
    • 1970-01-01
    • 2013-03-08
    • 2016-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多