TStringList.LoadFromFile - 大文本文件的例外

时间:2014-11-19 02:28:15

标签: delphi delphi-xe2 filestream readfile tstringlist

我正在运行Delphi RAD Studio XE2。

我有一些非常大的文件,每个文件都包含大量的行。线条本身很小 - 只有3个标签分隔的双打。我想使用TStringList将文件加载到TStringList.LoadFromFile,但这会引发大文件异常。

对于200万行(约1GB)的文件,我得到EIntOverflow例外。对于较大的文件(例如,2000万行和大约10GB),我得到ERangeCheck异常。

我有32GB的RAM可供使用,我只是想加载这个文件并快速使用它。这里发生了什么,我有什么其他选择?我可以使用带有大缓冲区的文件流将此文件加载到TStringList中吗?如果是这样,请提供一个例子。

1 个答案:

答案 0 :(得分:14)

当Delphi在Delphi 2009中切换到Unicode时,TStrings.LoadFromStream()方法(内部TStrings.LoadFromFile()调用)对于大型流/文件来说效率非常

在内部,LoadFromStream()整个文件作为TBytes读入内存,然后使用UnicodeString将其转换为TEncoding.GetString()(进行解码)将字节转换为TCharArray,将其复制到最终UnicodeString中,然后释放数组),然后解析UnicodeStringTBytes仍然在内存中)添加根据需要将子字符串放入列表中。

因此,就在LoadFromStream()退出之前,内存中有四个文件数据副本 - 三个副本占用更差的filesize * 3个字节的内存(其中每个copy使用自己的连续内存块+一些MemoryMgr开销,并为解析的子串提供一个副本!当然,当LoadFromStream()实际退出时,前三个副本被释放。但这解释了为什么在到达那个点之前你会遇到内存错误 - LoadFromStream()试图使用3-4 GB内存来加载1GB文件,而RTL的内存管理器无法处理。

如果您想将大文件的内容加载到TStringList,最好使用TStreamReader代替LoadFromFile()TStreamReader使用缓冲文件I / O方法以小块读取文件。只需在循环中调用其ReadLine()方法,Add()将每一行调用到TStringList。例如:

//MyStringList.LoadFromFile(filename);
Reader := TStreamReader.Create(filename, true);
try
  MyStringList.BeginUpdate;
  try
    MyStringList.Clear;
    while not Reader.EndOfStream do
      MyStringList.Add(Reader.ReadLine);
  finally
    MyStringList.EndUpdate;
  end;
finally
  Reader.Free;
end;

也许有一天,可能会重写LoadFromStream()以在内部使用TStreamReader