标签: tstringlist

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

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

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

TStringList.LoadFromFile - 大文本文件的异常

代码示例:

//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;
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

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

var …
Run Code Online (Sandbox Code Playgroud)

delphi text tstringlist readline delphi-10.2-tokyo

5
推荐指数
1
解决办法
3341
查看次数

在记录中包装TStringList

我倾向于使用Delphi的TStringList进行文本操作,所以我写了很多程序/函数,如:

var
  TempList: TStringList;
begin
  TempList:= TStringList.Create;
  try
    // blah blah blah do stuff with TempList   


  finally
    TempList.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

切断创建和释放这样一个常见的实用程序类会很好.

因为我们现在有方法的记录,是否可以在记录中包装类似TStringList的类,所以我可以:

var
  TempList: TRecordStringList;
begin
  // blah blah blah do stuff with TempList   


end;
Run Code Online (Sandbox Code Playgroud)

delphi records tstringlist

4
推荐指数
1
解决办法
2346
查看次数

在Delphi Prism中替换TStringList.

我正在将用Delphi 2007 .Net编写的应用程序迁移到Delphi Prism,这是替换TStringList和TStrings类的最佳选择吗?

提前致谢.

再见.

delphi tstringlist oxygene delphi-prism

4
推荐指数
2
解决办法
1657
查看次数

Delphi - 读取文件到StringList,然后删除并写回文件

我目前正在开发一个程序来生成Delphi 2010中的文件哈希.作为其中的一部分,我可以选择创建用户预设,例如用户可以创建/保存/删除的哈希算法的预定义选择.我有创建和加载代码正常工作.它使用ComboBox并从文件"fhpre.ini"加载,在此文件中是用户预设,格式为: -

PresetName
PresetCode(12位数字符串,使用0表示不散列,1表示do)

在应用程序加载时,它会将此文件中的数据加载到ComboBox和一个数组中,其中ComboBox的ItemIndex与数组中0和1的相应正确字符串相匹配.

现在我需要实现一项功能,让用户从列表中删除预设.到目前为止,我的代码如下,

procedure TForm1.Panel23Click(Sender : TObject);

var
fil : textfile;
contents : TStringList;
x,i : integer;
filline : ansistring;
filestream : TFileStream;

begin //Start Procedure

//Load data into StringList
contents := TStringList.Create;
fileStream := TFileStream.Create((GetAppData+'\RFA\fhpre.ini'), fmShareDenyNone);
Contents.LoadFromStream(fileStream);
fileStream.Destroy();

//Search for relevant Preset
i := 0;
if ComboBox4.Text <> Contents[i] then
begin
Repeat
i := i + 1;
Until ComboBox4.Text = Contents[i];
end;

contents.Delete(i); //Delete Relevant Preset Name
contents.Delete(i); //Delete Preset Digit String

//Write StringList back …
Run Code Online (Sandbox Code Playgroud)

delphi file tstringlist

4
推荐指数
2
解决办法
1万
查看次数

TStringList和TThread没有释放所有内存

使用的版本: Delphi 7.

我正在开发一个在Virtual ListView上执行简单for循环的程序.数据存储在以下记录中:

type TList=record
  Item:Integer;
  SubItem1:String;
  SubItem2:String;
end;
Run Code Online (Sandbox Code Playgroud)

项目是索引.SubItem1操作的状态(成功与否).SubItem2文件的路径.在循环加载每个文件,做一些操作,然后保存.操作发生在TStringList中.文件大约每个2mb.

现在,如果我在主窗体上执行操作,它可以完美地工作.

多线程,存在巨大的内存问题.不知何故,TStringList似乎没有被完全释放.在3-4k文件之后,我得到一个EOutofMemory异常.有时候,软件会停留在500-600mb,有时候不会.在任何情况下,TStringList始终返回EOutofMemory异常,并且不再可以加载任何文件.在具有更多内存的计算机上,获取异常需要更长时间.

其他组件也会发生同样的事情.例如,如果我使用Synapse的THTTPSend,过了一段时间,软件无法创建任何新线程,因为内存消耗太高.它大概是500-600mb,而它应该是,最大,100mb.在主窗体上,一切正常.

我想这个错误就在我身边.也许我不太了解线程.我试图释放Destroy事件中的所有内容.我尝试过FreeAndNil程序.我一次只尝试一个线程.我尝试手动释放线程(没有FreeOnTerminate ......)

没运气.

所以这是线程代码.这只是基本的想法; 不是所有操作的完整代码.如果我删除LoadFile prodecure,一切都很好.根据线程池为每个文件创建一个线程.

unit OperationsFiles;

interface

uses Classes, SysUtils, Windows;

type
 TOperationFile = class(TThread)
 private
  Position : Integer;
  TPath, StatusMessage: String;
  FileStringList: TStringList;
  procedure UpdateStatus;
  procedure LoadFile;
 protected
  procedure Execute; override;
 public
  constructor Create(Path: String; LNumber: Integer);
 end;

implementation

uses Form1;

procedure TOperationFile.LoadFile;
begin
 try …
Run Code Online (Sandbox Code Playgroud)

memory delphi ram tstringlist tthread

4
推荐指数
1
解决办法
2322
查看次数

具有非ANSI文件的TStringList行为

在我的应用程序中,当我想导入文件时,我使用TStringList.

但是,当有人从Excel导出数据时,文件编码是UCS-2 Little Endian,而TStringList无法读取数据.

有什么方法可以验证这种情况,识别文本编码并向用户发送提示文本不兼容的警告?

为了清楚起见,用户将只提供纯文本..通讯和数字,否则,我必须发送警告.

没有BOM的Unicode文件很好.(TStringList可以读取它!)
ANSI文件也是.(TStringList可以读取它!)
如果有一种方法可以删除它,即使带有BOM的Unicode也会很好.(TStringList可以读取它!,但是带有"i"">>"和"reverse?"字符,属于BOM字节)

delphi encoding file tstringlist delphi-6

4
推荐指数
1
解决办法
1068
查看次数

如何在字符串中存储和加载键值对列表?

我有一个字符串列表和它们要替换的值.我正在尝试将它们组合在一个列表中,'O'='0',' .'='.', ...因此我很容易编辑它并添加更多对替换.

现在我能想到的最好方法是:

var
  ListaLimpeza : TStringList;
begin
  ListaLimpeza := TStringList.Create;

  ListaLimpeza.Delimiter := '|';
  ListaLimpeza.QuoteChar := '"';
  ListaLimpeza.DelimitedText := 'O=0 | " .=."';

  ShowMessage('1o Valor = '+ListaLimpeza.Names[1]+' e 2o Valor = '+ListaLimpeza.ValueFromIndex[1]);
Run Code Online (Sandbox Code Playgroud)

这是有效的,但它对于视觉效果并不好,因为我不能像之前的那样对字符串(对于ex ' .')进行编码(对于SPACE字符来说是非常直观的),只有像(" .)这样=才能分配名称和值在TStringList中.

delphi string tstringlist

4
推荐指数
1
解决办法
2万
查看次数

有什么方法可以让 TStringList.CommaText 不使用引号转义逗号?

我正在做一些代码生成工作,我需要做的一件事是创建一个函数调用,其中一个参数是函数调用,如下所示:

result := Func1(x, y, Func2(a, b, c));
Run Code Online (Sandbox Code Playgroud)

TStringList.CommaText 对于生成参数列表非常有用,但是当我遍历树以构建外部函数调用时,我最终得到的结果如下:

result := Func1(x, y, "Func2(a, b, c)");
Run Code Online (Sandbox Code Playgroud)

它引用了第三个参数,因为它包含逗号,并且产生了无效代码。但是我不能做一些像 StringReplace 所有双引号为空字符串这样简单的事情,因为函数参数很可能是一个带有双引号的字符串。有没有办法让它不转义包含逗号的行?

delphi code-generation escaping tstringlist

3
推荐指数
1
解决办法
7290
查看次数

记录中的Delphi Stringlist

是否有可能在记录中有一个字符串列表?例如

TImportStats = record
  ATotal:Integer;
  BTotal:String;
  AList:TStringist;
end;
Run Code Online (Sandbox Code Playgroud)

如果我认为我需要在使用记录之前创建它?

delphi record tstringlist

3
推荐指数
1
解决办法
2246
查看次数

如何识别Delphi是否创建了StringList对象

我在私有部分声明了TStringList的变量.在按钮单击事件中,我想访问该TStringList对象.

sVariable:= TStringList.Create;
sVariable.add('Test1');
Run Code Online (Sandbox Code Playgroud)

现在每当我点击该按钮时,每次将其新创建的内存分配给该变量.是否有任何属性/函数可用于确定是否为该变量创建了对象,并且它也不会给出访问冲突错误?

delphi tstringlist

3
推荐指数
2
解决办法
3555
查看次数