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

2024-01-25

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

该文件中的每一行都包含一个名称和等号,其余部分是数据。例如,SOMEUNIQUENAME=SomeStringValue。我打算在线程内保持文件打开一段时间。该线程执行传入请求以获取、设置或删除某些数据字段。我用WriteLn and ReadLn循环中,评估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种方法:

  • 字符串列表
  • 流读取器/流写入器
  • 文本文件

所有方法均以 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.

Output:

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 毕竟是一个不错的选择......

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以低级方式修改或删除文本文件中的一行? 的相关文章

随机推荐

  • 基于 Woocommerce 中产品类别的条件自定义结帐字段

    我正在使用 woocommerce 作为一个非营利组织的网站 该网站出售课程门票和活动门票 当有人报名参加课程时 需要列出他们的紧急联系信息并同意免责 当他们购买活动门票时 非营利组织不需要紧急联系信息或责任免除 所以 他们希望这些字段仅在
  • rails 列不能为空:

    我注意到我的应用程序会自动将所有流程设置为在创建后立即完成 我浏览了一下 找不到为什么在没有被告知的情况下更新日期 但我发现我的观点之一是寻找一个不存在的字段 我创建了 完整 字段 将其设置为非空布尔值 然后再次尝试 我再次将其自动设置为
  • WinRT:如何将 WriteableBitmap 保存到本地文件夹

    如何在 WinRT 中使用 C 将 WriteableBitmap 保存到本地文件夹 您可以检查 WinRT XAML Toolkit 中的一组扩展方法来完全满足您的需要 http winrtxamltoolkit codeplex com
  • UIActivityViewController 在设备上呈现时崩溃

    我在项目中添加 ios 默认共享表 UIActivityViewController 时遇到问题 它在模拟器上运行良好 但在使用 USB 电缆或 testflight 在设备 iPhone 上运行时会崩溃 我收到的错误消息是 由于未捕获的异
  • 将 .net 4.5 应用程序降级到 4.0

    我想将 net 库从框架版本 4 5 降级到 net 4 0 我使用 nuget 安装了几个库 Microsoft AspNet WebApi Client 及其依赖项 Newtonsoft Json System Net Http Mic
  • 我没有关闭管道末端的一个,有什么问题发生吗?

    我使用管道在父进程和子进程之间进行通信 我读的书说 在父进程中 我必须关闭pipefd 1 但我没有这样做 也没有发生其他事情 所以我的问题是 如果我不关闭pipefd 1 有什么吗 不受控制 此致 int pipefd 2 if pipe
  • 用Java编写一个丢弃网络数据包的个人防火墙[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我想用Java编写一个可以丢弃网络数
  • Android:谷歌地图 API 版本 2

    我按照步骤配置 Google Maps Android API v2官方步骤 https developers google com maps documentation android start我使用的是安卓3 1版本 我运行项目时遇到
  • UITextField,1个字符后自动移至下一个

    场景 我有 4 个 UITextField 仅接受 1 个字符 简单的 问题 输入 1 个字符后 我希望下一个 TextField 自动变为活动状态 而不必按下一个 即我正在使用 UIKeyboardTypeNumberPad 并且没有 N
  • 如何将 python 中的目标代码转换为 kotlin?

    我正在开发一个将使用分水岭的图像分割应用程序 为此 我找到了一个需要在 python 中使用的代码 但是 我很难转换为 kotlin 因为 Mat Mat 没有 Zero likes 函数 只有 Zero 函数 我使用的是opencv 3
  • MongoDB shell:如何搜索与名称或正则表达式匹配的集合

    当我使用 show collections 时 它返回一个相当长的所有集合的列表 如何编写查询来返回与模式匹配的集合 我希望有像 db collections name pattern 这样的东西 但找不到 您可以使用db getColle
  • 在 C++ 中释放指针两次或更多次时会发生什么?

    int main Employee e new Employee delete e delete e delete e return 0 You get 未定义的行为如果你尝试delete一个对象多次通过指针 这意味着几乎任何事情都可能发生
  • 如果我想要抓取的图像受 cloudflare 保护并给出 1020 错误,有没有办法使用 Cheerio 抓取网站?

    我正在尝试创建一个漫画抓取网站作为个人项目 就在我完成整个网站时 我知道图像无法被我的网站抓取或查看 当我尝试转到图像的链接时 我收到 1020 错误 指出访问被拒绝 有什么方法可以绕过该错误 而无需从网站所有者那里获取授权令牌 如果答案是
  • 如果子div为空,jQuery隐藏父div

    我环顾四周 发现了很多与此相关的问题 但没有一个解决方案适合我 我有这样的结构 div class pricetag div class price 400 div div div class pricetag div class pric
  • 将 CGImageRef 保存为 PNG 文件时出错? (电弧引起的?)

    这段代码曾经可以工作 但是我认为 Xcode 的新 ARC 可能已经杀死了它 void applicationDidFinishLaunching NSNotification aNotification CGDirectDisplayID
  • 如何知道任务是否同步完成?

    我依稀记得有一个属性可以告诉我们任务是否同步执行 但我刚才记不清了 或者可能没有 我正在混淆IAsyncResult CompletedSynchronously和这个 检查一下 Task IAsyncResult CompletedSyn
  • 全屏、沉浸模式、禁用向左滑动导航栏

    是否可以在全屏沉浸模式下禁用打开主导航栏的向左滑动手势 使其只能从顶部滑动打开 在开发全屏游戏时 必须进行大量设计以防止用户意外打开它 这非常烦人 提前致谢 EDIT 抱歉 只是为了澄清一下 我正在谈论沉浸式模式下的水平锁定全屏游戏 禁用使
  • Python Pandas:如何从列表列创建二进制矩阵?

    我有一个 Python Pandas DataFrame 如下所示 1 0 a b 1 c 2 d 3 e a b是表示用户特征列表的字符串 如何将其转换为用户特征的二进制矩阵 如下所示 a b c d e 0 1 1 0 0 0 1 0
  • 在动态有向图中寻找最小循环路径

    我最近遇到这 编辑 问题A http www scribd com doc 109453858 2 Spotify Codequest 2012今年早些时候 Spotify 的黑客挑战赛中出现了一个有趣的问题 该挑战涉及确定火车卡车路口的切
  • 以低级方式修改或删除文本文件中的一行?

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