我正在使用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;
我有一些测试代码可用于完善我的例程,但这似乎相对快速,高效且足够。我要感谢大家为我解雇灰烬而做出的回应!
答案 0 :(得分:0)
作为(非常快速的)解决方法,您可以尝试使用https://github.com/Zeus64/alcinoe中的TALStringlist(只需用TalStringList替换代码TStringList)。这不是一个很干净的方法,但是TALStringlist将保留在Unicode UTF-8中,将默认UTF 16字符串使用的内存减少2。由于您有700万条线(约100个字符),平均约为700 Mb,因此可以在32位上工作