delphi - 使用 TStreamReader 和 TStringList 处理非常大的文本文件

标签 delphi text readline delphi-10.2-tokyo tstringlist

我正在使用 Embarcadero 的 Rad Studio Delphi (10.2.3),并且在读取非常大的文本文件(700 万行以上,每行都不同,行长度可以是 1 到 ~200 个字符等)时遇到内存问题.)。我对 Delphi 编程相当陌生,所以在发帖之前我已经搜索过 SO 和 Google 寻求帮助。

我最初实现了一个 TStringList 并使用 LoadFromFile 方法读取文件,但是当处理的文本文件变得足够大时,这会失败。然后,我实现了一个 TStreamReader 并使用 ReadLn 使用此处找到的基本代码填充 TStringList:

TStringList.LoadFromFile - Exceptions with Large Text Files

代码示例:

//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;

这一直很有效,直到我需要处理的文件变得巨大(约 700 万行以上)。看起来 TStringList 变得太大以至于内存不足。我说“出现”是因为我实际上无权访问正在运行的文件,并且所有错误信息都是由我的客户通过电子邮件提供的,这使得这个问题变得更加困难,因为我无法简单地在 IDE 中调试它.

代码是32位编译的,我无法使用64位编译器。我也不能包括数据库系统之类的。不幸的是,我有一些严格的限制。我需要加载每一行以查找模式并将这些行与其他行进行比较以查找“模式中的模式”。我很抱歉在这里说得很含糊。

底线是——有没有一种方法可以在不使用 TStringList 的情况下访问文本文件中的每一行,或者也许有更好的方法来处理 TStringList 内存?

也许有一种方法可以将 StreamReader 中的特定行 block 加载到 TStringList 中(例如,读取前 100,000 行并处理,接下来的 100,000 行等),而不是一次加载所有内容?我想我可以写一些东西来处理可能的“ block 间”模式。

预先感谢您的任何帮助和建议!

***** 已编辑并更新 *****

好的,这是我需要实现的基本解决方案:

var
  filename: string;
  sr: TStreamReader;
  sl: TStringList;
  total, blocksize: integer;
begin
  filename := 'thefilenamegoeshere';
  sl := TStringList.Create;
  sr := TStreamReader.Create(filename, true);
  sl.Capacity := sr.BaseStream.Size div 100;
  total := 0; // Total number of lines in the file (after it is read in)
  blocksize := 10000; // The number of lines per "block"
  try
    sl.BeginUpdate;
    try
      while not sr.EndOfStream do
        begin
          sl.Clear;
          while not (sl.Count >= blocksize) do
            begin
              sl.Add(sr.ReadLine);
              total := total + 1;
              if (sr.EndOfStream = true) then break;
            end;
          // Handle the current block of lines here
        end;
    finally
      sl.EndUpdate;
    end;
  finally
    sr.Free;
    sl.Free;
  end;
end;

我有一些测试代码,我将用它们来完善我的例程,但这似乎相对快速、高效且足够。我要感谢大家的回应,让我的灰质兴奋不已!

最佳答案

作为(非常)快速的修复,您可以尝试使用https://github.com/Zeus64/alcinoe中的TALStringlist(只需在代码中将TStringList替换为TalStringList) 。这不是一个非常干净的方法,但 TALStringlist 将保留在 unicode UTF-8 中,将默认 UTF 16 字符串使用的内存减少 2。由于您有 7 000 000 行,大约 100 个字符,这意味着大约 700 Mb,这可以在 32 位上运行

关于delphi - 使用 TStreamReader 和 TStringList 处理非常大的文本文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52856829/

相关文章:

delphi - 分析器能够在执行某些过程时开始分析

delphi - TDateTimePicker 和日期

javascript - 使用 PIXI JS 更改弯曲文本中的字体大小

c++ - 如何在 ncurses 应用程序中使用 readline?

ruby-on-rails - 如何编译带有 Readline 支持的 Ruby?

node.js - 如何在 Node.js 中为 readline 提供默认答案

c# - 正确地将字节从 C++ 转换为 delphi AnsiString

c++ - 检测应用程序是否在笔记本电脑上运行

python - 仅在行尾显示为菱形问号的字符(Python>文本)

javascript - 如何使用 node.js 为文本文件的每一行创建一个数组条目