【问题标题】:Big strings: System.OutOfMemoryException大字符串:System.OutOfMemoryException
【发布时间】:2011-03-07 12:17:24
【问题描述】:
var fileList = Directory.GetFiles("./", "split*.dat");
int fileCount = fileList.Length;
int i = 0;
foreach (string path in fileList)
{
    string[] contents = File.ReadAllLines(path); // OutOfMemoryException
    Array.Sort(contents);
    string newpath = path.Replace("split", "sorted");
    File.WriteAllLines(newpath, contents);
    File.Delete(path);
    contents = null;
    GC.Collect();

    SortChunksProgressChanged(this, (double)i / fileCount);
    i++;
}

对于包含 ~20-30 大行(每行 ~20mb)的文件,当我执行 ReadAllLines 方法时,我有 OutOfMemoryException。为什么会引发此异常?我该如何解决? 附言我在 MacOS 上使用 Mono

【问题讨论】:

  • 那么不要ReadAllLines,一次读一行?虽然 20mb 行很疯狂:/
  • 我必须实现外部排序并向我的老师展示它适用于比我的 RAM 更大的文件。而且我认为对于仅包含 200-300 行且每行为 20 mb 的文件,排序算法会更快。
  • 它是什么类型的数据?如果您只读取每行的前 x 个字符并按这些字符进行排序,那么您的排序是否足够?
  • 每个文件 20-30 或 200-300 行?
  • 好吧,我们在这里告诉你,你走上了一条死路。该文件是故意设计的,因此这不起作用;)

标签: c# .net mono out-of-memory


【解决方案1】:

您应该始终非常小心地执行具有潜在无限结果的操作。在你的情况下阅读文件。正如您所提到的,文件大小和/或行长度是无限的。

答案在于读取“足够”的一行以进行排序,然后跳过字符直到下一行并读取下一个“足够”。您可能希望创建一个行索引查找,以便当您达到不明确的行排序顺序时,您可以返回以从行中获取更多数据(查找文件位置)。当您返回时,您只需读取下一个可排序的块即可消除冲突行。

您可能需要考虑文件编码,除非您知道它是每个字符一个字节,否则不要直接使用字节。

内置排序没有你想的那么快。

旁注:

  1. 如果你调用 GC.* 你可能做错了
  2. 设置 contents = null 对你没有帮助
  3. 如果您使用 foreach 并维护索引,那么使用 for(int i...) 可能会更好,以提高可读性

【讨论】:

    【解决方案2】:

    好的,让我给你一个提示,帮助你完成家庭作业。如您所知,将完整的文件加载到内存中是行不通的,因为它是作为分配的先决条件给出的。你需要找到一种方法,在你去的时候懒惰地从磁盘加载数据,并尽快丢弃尽可能多的数据。因为单行可能太大,您必须一次处理一个字符。

    尝试创建一个代表一行抽象的类,例如通过包装该行的起始索引和结束索引。当您让此类实现IComparable<T> 时,它允许您将该行与其他行进行排序。同样,诀窍是能够一次从文件中读取一个字符。您需要直接与Streams (File.Open) 合作。

    当你这样做时,你将能够像这样编写你的应用程序代码:

    List<FileLine> lines = GetLines("fileToSort.dat");
    
    lines.Sort();
    
    foreach (var line in lines)
    {
        line.AppendToFile("sortedFile.dat");
    }
    

    您的任务是实现GetLines(string path) 并创建FileLine 类。

    请注意,我假设实际行数足够小,以至于List&lt;FileLine&gt; 可以放入内存(这意味着大约最多 40,000,000 行)。如果行数可以更高,你甚至需要更灵活的方法,但既然你说的是 20 到 30 行,这应该不是问题。

    【讨论】:

      【解决方案3】:

      基本上你的做法是公牛。你违反了作业的约束,而这个约束是为了让你思考更多。

      如你所说:

      我必须实现外部排序并向我的老师表明它适用于比我更大的文件 内存

      好的,所以你认为你将如何阅读文件;)这是故意的。 ReadAllLiens 不实现增量外部排序。结果,它吹了。

      【讨论】:

      • 你是对的,但你表达你的答案的方式是一个明显的巨魔诱饵。
      • @skolima:TomTom 就是这样滚动的 :-)
      猜你喜欢
      • 2017-06-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-16
      • 2012-02-17
      • 2016-03-05
      • 1970-01-01
      • 2021-12-23
      相关资源
      最近更新 更多