使用TStreamReader和TStringList

时间:2018-10-17 14:04:28

标签: 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加载到TStringList中(例如,读取前100,000行并进行处理,接下来的100,000行等),而不是一次加载所有行?我想我可以写一些东西来处理可能的“块间”模式。

在此先感谢您提供所有帮助和建议!

*****编辑为更新*****

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

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;

我有一些测试代码可用于完善我的例程,但这似乎相对快速,高效且足够。我要感谢大家为我解雇灰烬而做出的回应!

1 个答案:

答案 0 :(得分:0)

作为(非常快速的)解决方法,您可以尝试使用https://github.com/Zeus64/alcinoe中的TALStringlist(只需用TalStringList替换代码TStringList)。这不是一个很干净的方法,但是TALStringlist将保留在Unicode UTF-8中,将默认UTF 16字符串使用的内存减少2。由于您有700万条线(约100个字符),平均约为700 Mb,因此可以在32位上工作