Delphi TFileStream逐段读取巨大的文件

Delphi TFileStream逐段读取巨大的文件,delphi,Delphi,今天早些时候,我在这里提出了一个问题,问我扫描计算机中文件的方法是否正确。作为解决方案,我收到了一些提示,其中一个解决方案我认为:“这需要紧急解决!”,是关于内存溢出,一旦我完全在内存中读取文件。因此,我开始试图找到一种方法来逐条读取文件,我得到了一些东西(错误/伪造),我需要一些帮助来找出如何正确地执行此操作。 目前的方法很简单,如下所示: procedure ScanFile(FileName: string); const MAX_SIZE = 100*1024*1024; var

今天早些时候,我在这里提出了一个问题,问我扫描计算机中文件的方法是否正确。作为解决方案,我收到了一些提示,其中一个解决方案我认为:“这需要紧急解决!”,是关于内存溢出,一旦我完全在内存中读取文件。因此,我开始试图找到一种方法来逐条读取文件,我得到了一些东西(错误/伪造),我需要一些帮助来找出如何正确地执行此操作。 目前的方法很简单,如下所示:

procedure ScanFile(FileName: string);
const
  MAX_SIZE = 100*1024*1024;
var
  i, aux, ReadLimit: integer;
  MyFile: TFileStream;
  Target: AnsiString;
  PlainText: String;
  Buff: array of byte;
  TotalSize: Int64;
begin
  if (POS('.exe', FileName) = 0) and (POS('.dll', FileName) = 0) and
      (POS('.sys', FileName) = 0) then //yeah I know it's not the best way...
    begin
      try
        MyFile:= TFileStream.Create(FileName, fmOpenRead);
      except on E: EFOpenError do
        MyFile:= NIL;
      end;
      if MyFile <> NIL then
      try
        TotalSize:= MyFile.Size;
        while TotalSize > 0 do begin
          ReadLimit:= Min(TotalSize, MAX_SIZE);
          SetLength(Buff, ReadLimit);
          MyFile.ReadBuffer(Buff[0], ReadLimit);
          PlainText:= RemoveNulls(Buff); //this is to transform the array of bytes in string, I posted the code below too...
          for i:= 1 to Length(PlainText) do
            begin //Begin the search..
            end;
          dec(TotalSize, ReadLimit);
         end;
  finally
    MyFile.Free;
  end;
end;
过程扫描文件(文件名:字符串);
常数
最大尺寸=100*1024*1024;
变量
i、 aux,ReadLimit:整数;
MyFile:TFileStream;
目标:AnsiString;
纯文本:字符串;
Buff:字节数组;
TotalSize:Int64;
开始
如果(POS('.exe',文件名)=0)和(POS('.dll',文件名)=0)和
(POS('.sys',FileName)=0)然后//是的,我知道这不是最好的方式。。。
开始
尝试
MyFile:=TFileStream.Create(文件名,fmOpenRead);
除了在E:EFOpenError do上
MyFile:=NIL;
终止
如果我的文件为零,那么
尝试
TotalSize:=MyFile.Size;
当TotalSize>0时,开始
读取限制:=最小值(总大小、最大大小);
设置长度(Buff、ReadLimit);
ReadBuffer(Buff[0],ReadLimit);
纯文本:=RemoveNulls(浅黄色)//这是转换字符串中的字节数组,我也发布了下面的代码。。。
对于i:=1到长度(纯文本)do
开始//开始搜索。。
终止
dec(总大小,读取限制);
终止
最后
免费的;
终止
终止
RemoveNulls的代码为:

function RemoveNulls(const Buff: array of byte): String;
var
  i: integer;
begin
  for i:= 0 to Length(Buff) do
    begin
      if Buff[i] <> 0 then
        Result:= Result + Chr(Ord(Buff[i]));
    end;
end;
函数RemoveNulls(const Buff:byte数组):字符串;
变量
i:整数;
开始
对于i:=0到长度(Buff)do
开始
如果Buff[i]0,则
结果:=Result+Chr(Ord(Buff[i]);
终止
终止
好的,到目前为止,我在这段代码中遇到的问题是:

1-每次重复while,我都会消耗更多的内存,而我原本只希望获得MAX_SIZE变量中描述的最大100MB,对吗?

2-我创建了一个文件,其中包含两个应该过滤的内容,由于未知原因,我得到了大约10个重复出现的内容,看起来我正在重复扫描该文件


我感谢你们的帮助,如果有人已经完成了这种代码,请在这里发布,我不会假装重新创建轮子…

我想说RemoveNulls是你的问题。假设您只是将100MB读入传递给RemoveNulls的字符串中。然后分配一个长度为1的字符串。重新分配到长度2。然后是长度3。然后是长度4。以此类推,一直到长度100*1024*1024

这一过程将使你的记忆支离破碎,而且速度惊人。当性能很重要时,应避免堆分配。你根本不需要它。读取文件的一块,然后直接在您读取的缓冲区中搜索

我可以看到您的代码存在各种问题:

  • 正如我在前面的问题中所描述的,您的文件扩展名检查被破坏
  • 正如我在前面的问题中所描述的,您没有正确处理异常
  • RemoveNulls中的for循环存在缓冲区溢出。从low()循环到high()

  • 无法对搜索代码进行评论,因为这在问题中不存在。

    我认为RemoveNulls是您的问题。假设您只是将100MB读入传递给RemoveNulls的字符串中。然后分配一个长度为1的字符串。重新分配到长度2。然后是长度3。然后是长度4。以此类推,一直到长度100*1024*1024

    这一过程将使你的记忆支离破碎,而且速度惊人。当性能很重要时,应避免堆分配。你根本不需要它。读取文件的一块,然后直接在您读取的缓冲区中搜索

    我可以看到您的代码存在各种问题:

  • 正如我在前面的问题中所描述的,您的文件扩展名检查被破坏
  • 正如我在前面的问题中所描述的,您没有正确处理异常
  • RemoveNulls中的for循环存在缓冲区溢出。从low()循环到high()

  • 无法对搜索代码进行评论,因为这在问题中不存在。

    请参见@DavidHeffernan。这是大量我不理解的代码。我知道它可能会解决我的问题,但如果可能的话,我更喜欢做一些简单的事情。感谢您的关注。Re:2)和4)这是因为您正从文件中请求100MB,而您必须请求
    Min(Count,MAX\u SIZE)
    。我建议重写(为了简单的练习,暂时不要处理异常)。@FreeConsulting是的,我现在做了:
    而Count>0 do begin N:=Min(Count,MAX_SIZE);设置长度(Buff,N);MyFile.ReadBuffer(Buff[0],N)并解决了2和4。。。非常感谢。请不要在继续的过程中修改这个问题,评论中的“2)和“4”现在没有多大意义。请看@DavidHeffernan。这是大量的代码,我不理解。我知道它可能会解决我的问题,但如果可能的话,我更喜欢做一些简单的事情。感谢您的关注。Re:2)和4)这是因为您正从文件中请求100MB,而您必须请求
    Min(Count,MAX\u SIZE)
    。我建议重写(为了简单的练习,暂时不要处理异常)。@FreeConsulting是的,我现在做了:
    而Count>0 do begin N:=Min(Count,MAX_SIZE);设置长度(Buff,N);MyFile.ReadBuffer(Buff[0],N)并解决了2和4。。。非常感谢。请不要在你继续的过程中修改问题,评论中的“2”和“4”现在没有多大意义。大卫,很抱歉回答得太晚。是的,我检查过了,当我不调用RemoveNulls时,程序工作时没有内存泄漏。这可以通过循环fr来修复