gpt4 book ai didi

delphi - 以低级方式修改或删除文本文件中的一行?

转载 作者:行者123 更新时间:2023-12-01 19:33:56 25 4
gpt4 key购买 nike

我正在 Delphi 中处理文本文件,并且我不希望使用加载/保存字符串列表的方法。我打算维护一个开放的文件流,在其中读取和写入数据,将大量数据保存在硬盘上而不是内存中。我有一个简单的概念,即向文本文件写入新行并读取它们,但是当涉及到修改和删除它们时,我找不到任何好的资源。

该文件中的每一行都包含一个名称和等号,其余的是数据。例如,SOMEUNIQUENAME=SomeStringValue。我打算在线程内保持文件打开一段时间。该线程执行传入请求以获取、设置或删除某些数据字段。我在循环中使用 WriteLnReadLn 来评估 EOF。下面是我如何读取数据的示例:

FFile = TextFile;

...

function TFileWrapper.ReadData(const Name: String): String;
var
S: String; //Temporary line to be parsed
N: String; //Temporary name of field
begin
Result:= '';
Reset(FFile);
while not EOF(FFile) do begin
ReadLn(FFile, S);
N:= UpperCase(Copy(S, 1, Pos('=', S)-1));
if N = UpperCase(Name) then begin
Delete(S, 1, Pos('=', S));
Result:= S;
Break;
end;
end;
end;

...然后我触发一个事件,通知发送者结果。这些请求位于队列内,该队列有点像这些请求的消息泵。该线程只是重复处理队列中的下一个请求,类似于典型应用程序的工作方式。

我已经准备好了能够写入和删除这些字段的程序,但我不知道需要做什么才能实际对文件执行操作。

procedure TFileWrapper.WriteData(const Name, Value: String);
var
S: String; //Temporary line to be parsed
N: String; //Temporary name of field
begin
Result:= '';
Reset(FFile);
while not EOF(FFile) do begin
ReadLn(FFile, S);
N:= UpperCase(Copy(S, 1, Pos('=', S)-1));
if N = UpperCase(Name) then begin
//How to re-write this line?
Break;
end;
end;
end;

procedure TFileWrapper.DeleteData(const Name: String);
var
S: String; //Temporary line to be parsed
N: String; //Temporary name of field
begin
Result:= '';
Reset(FFile);
while not EOF(FFile) do begin
ReadLn(FFile, S);
N:= UpperCase(Copy(S, 1, Pos('=', S)-1));
if N = UpperCase(Name) then begin
//How to delete this line?
Break;
end;
end;
end;

最后,我需要避免将整个文件加载到内存中才能完成此任务。

最佳答案

我发现这是一个有趣的问题,所以我制作了一个小型控制台应用程序。

我用了3种方法:

  • TStringList
  • 流读取器/流写入器
  • 文本文件

所有方法均以大小为 10kb 的文本文件和大小为 1Mb 的文本文件计时并重复 100 次。程序如下:

program Project16;

{$APPTYPE CONSOLE}

uses
SysUtils, Classes, StrUtils, Diagnostics, IOUtils;

procedure DeleteLine(StrList: TStringList; SearchPattern: String);

var
Index : Integer;

begin
for Index := 0 to StrList.Count-1 do
begin
if ContainsText(StrList[Index], SearchPattern) then
begin
StrList.Delete(Index);
Break;
end;
end;
end;

procedure DeleteLineWithStringList(Filename : string; SearchPattern : String);

var StrList : TStringList;

begin
StrList := TStringList.Create;
try
StrList.LoadFromFile(Filename);
DeleteLine(StrList, SearchPattern);
// don't overwrite our input file so we can test
StrList.SaveToFile(TPath.ChangeExtension(Filename, '.new'));
finally
StrList.Free;
end;
end;

procedure DeleteLineWithStreamReaderAndWriter(Filename : string; SearchPattern : String);

var
Reader : TStreamReader;
Writer : TStreamWriter;
Line : String;
DoSearch : Boolean;
DoWrite : Boolean;

begin
Reader := TStreamReader.Create(Filename);
Writer := TStreamWriter.Create(TPath.ChangeExtension(Filename, '.new'));
try
DoSearch := True;
DoWrite := True;
while Reader.Peek >= 0 do
begin
Line := Reader.ReadLine;
if DoSearch then
begin
DoSearch := not ContainsText(Line, SearchPattern);
DoWrite := DoSearch;
end;
if DoWrite then
Writer.WriteLine(Line)
else
DoWrite := True;
end;
finally
Reader.Free;
Writer.Free;
end;
end;

procedure DeleteLineWithTextFile(Filename : string; SearchPattern : String);

var
InFile : TextFile;
OutFile : TextFile;
Line : String;
DoSearch : Boolean;
DoWrite : Boolean;


begin
AssignFile(InFile, Filename);
AssignFile(OutFile, TPath.ChangeExtension(Filename, '.new'));
Reset(InFile);
Rewrite(OutFile);
try
DoSearch := True;
DoWrite := True;
while not EOF(InFile) do
begin
Readln(InFile, Line);
if DoSearch then
begin
DoSearch := not ContainsText(Line, SearchPattern);
DoWrite := DoSearch;
end;
if DoWrite then
Writeln(OutFile, Line)
else
DoWrite := True;
end;
finally
CloseFile(InFile);
CloseFile(OutFile);
end;
end;

procedure TimeDeleteLineWithStreamReaderAndWriter(Iterations : Integer);

var
Count : Integer;
Sw : TStopWatch;

begin
Writeln(Format('Delete line with stream reader/writer - file 10kb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithStreamReaderAndWriter('c:\temp\text10kb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
Writeln(Format('Delete line with stream reader/writer - file 1Mb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithStreamReaderAndWriter('c:\temp\text1Mb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
end;

procedure TimeDeleteLineWithStringList(Iterations : Integer);

var
Count : Integer;
Sw : TStopWatch;

begin
Writeln(Format('Delete line with TStringlist - file 10kb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithStringList('c:\temp\text10kb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
Writeln(Format('Delete line with TStringlist - file 1Mb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithStringList('c:\temp\text1Mb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
end;

procedure TimeDeleteLineWithTextFile(Iterations : Integer);

var
Count : Integer;
Sw : TStopWatch;

begin
Writeln(Format('Delete line with text file - file 10kb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithTextFile('c:\temp\text10kb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
Writeln(Format('Delete line with text file - file 1Mb, %d iterations', [Iterations]));
Sw := TStopwatch.StartNew;
for Count := 1 to Iterations do
DeleteLineWithTextFile('c:\temp\text1Mb.txt', 'thislinewillbedeleted=');
Sw.Stop;
Writeln(Format('Elapsed time : %d milliseconds', [Sw.ElapsedMilliseconds]));
end;

begin
try
TimeDeleteLineWithStringList(100);
TimeDeleteLineWithStreamReaderAndWriter(100);
TimeDeleteLineWithTextFile(100);
Writeln('Press ENTER to quit');
Readln;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

输出:

Delete line with TStringlist - file 10kb, 100 iterations
Elapsed time : 188 milliseconds
Delete line with TStringlist - file 1Mb, 100 iterations
Elapsed time : 5137 milliseconds
Delete line with stream reader/writer - file 10kb, 100 iterations
Elapsed time : 456 milliseconds
Delete line with stream reader/writer - file 1Mb, 100 iterations
Elapsed time : 22382 milliseconds
Delete line with text file - file 10kb, 100 iterations
Elapsed time : 250 milliseconds
Delete line with text file - file 1Mb, 100 iterations
Elapsed time : 9656 milliseconds
Press ENTER to quit

正如您所看到的,TStringList 是这里的获胜者。既然您无法使用 TStringList,那么 TextFile 毕竟是一个不错的选择...

附注:此代码省略了必须删除输入文件并将输出文件重命名为原始文件名的部分

关于delphi - 以低级方式修改或删除文本文件中的一行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13736707/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com