delphi - delphi TFileStream“内存不足”

标签 delphi memory runtime-error delphi-xe3 tfilestream

我在使用Delphi代码时遇到麻烦,这些代码使用TFileStream从文件读取数据块到动态数组。编写代码的最初目的是比较两个具有相同大小但可能具有不同日期和时间戳的文件的内容,以查看内容是否相同。通过将数据对从每个文件读取到单独的动态数组中,并将一个数组的每个字节与另一个数组的对应字节进行比较,即可完成此操作。

该代码多次调用TFileStream.Read。大约75次调用后,程序崩溃,并显示“内存不足”错误消息。

读取多大的数据块似乎无关紧要,似乎是导致错误消息的调用次数。

该代码是我编写的函数,只要程序遇到需要比较的两个文件(由于我不愿讨论的原因,它可能是四十个或五十个不同的文件对),该代码便在其他地方调用。无论是单个文件正在以小块读取,还是多个文件正在整体读取,都会发生“内存不足”错误。似乎是错误的决定因素是调用次数。

尽管我意识到可能有比下面显示的方法更优雅的文件比较方法,但我真正想知道的是,使用TFileStream和/或SetLength调用导致了内存问题。我尝试在每次调用后释放内存(如代码中所示),这似乎没有什么区别。

如果有人可以解释出什么问题了,我将不胜感激。

function Compare_file_contents(SPN,TPN : String; SourceFileSize : int64) : boolean;

var

  SF                : TFileStream; //First file of pair for comparison
  TF                : TFileStream; //Second file of pair
  SourceArray       : TBytes; // Buffer array to receive first file data
  TargetArray       : TBytes; //Buffer array to receive second file data
  ArrayLength       : int64; //Length of dynamic array
  Position          : int64; //Position within files to start each block of data read
  TestPosition      : int64; //Position within dynamic arrays to compare each byte
  MaxArrayLength    : integer; //Maximum size for the buffer arrays
  LastRun           : Boolean; //End first repeat loop

begin

{ The comparison has an arbitrary upper boundary of 100 MB to avoid slowing the
  the overall program. The main files bigger than this will be *.pst files that
  will most likely have new dates every time the program is run, so it will take
  about the same time to copy the files as it does to read and compare them, and
  it will have to be done every time.

  The function terminates when it is confirmed that the files are not the same.
  If the source file is bigger than 100 MB, it is simply assumed that they are
  not identical, thus Result = False. Also, LongInt integers (=integers) have
  a range of -2147483648..2147483647, so files bigger than 2 GB will have
  overflowed to a negative number. Hence the check to see if the file size is
  less than zero.

  The outer repeat ... until loop terminates on LastRun, but LastRun should only
  be set if SecondLastRun is True, because it will skip the final comparisons in
  the inner repeat ... until loop otherwise. }

  Result := True;
  LastRun := False;
  MaxArrayLength := 1024*1024;
  if (SourceFileSize > 100*1024*1024) or (SourceFileSize < 0) then Result := False
    else
      begin

{ The comparison is done by using TFileStream to open and read the data from
  the source and target files as bytes to dynamic arrays (TBytes). Then a repeat
  loop is used to compare individual bytes until a difference is found or all
  of the information has been compared. If a difference is found, Result is
  set to False. }

    if SourceFileSize > MaxArrayLength then ArrayLength := MaxArrayLength
      else ArrayLength := SourceFileSize;
    SF := TFileStream.Create(SPN,fmOpenRead);
    TF := TFileStream.Create(TPN,fmOpenRead);
    Position := 0;
    SetLength(SourceArray,ArrayLength);
    SetLength(TargetArray,ArrayLength);
    try
      SF.Read(SourceArray,ArrayLength);
      TF.Read(TargetArray,ArrayLength);
      Position := SF.Position;
    finally
      SF.Free;
      TF.Free;
    end;
      repeat
      TestPosition := 0;
        repeat
          if SourceArray[TestPosition] <> TargetArray[TestPosition] then
            Result := False;
          Inc(TestPosition);
        until (Result = False) or (TestPosition = ArrayLength);
        if SourceFileSize > Position then
          begin
            if SourceFileSize - Position - MaxArrayLength > 0 then
              ArrayLength := MaxArrayLength
              else ArrayLength := SourceFileSize - Position;
            SF := TFileStream.Create(SPN,fmOpenRead);
            TF := TFileStream.Create(TPN,fmOpenRead);
            SF.Position := Position;
            TF.Position := Position;
            try
              SF.Read(SourceArray,ArrayLength);
              TF.Read(TargetArray,ArrayLength);
              Position := SF.Position;
            finally
              SF.Free;
              TF.Free;
            end;
        end else LastRun := True;
      until (Result = False) or LastRun;
      Finalize(SourceArray);
      Finalize(TargetArray);
  end;
end; { Compare_file_contents }

最佳答案

这个例程似乎要复杂得多。我没有尝试调试它,而是为您提供了比较流的例程。

function StreamsEqual(Stream1, Stream2: TStream): Boolean;
const
  OneKB = 1024;
var
  Buffer1, Buffer2: array [0..4*OneKB-1] of Byte;
  SavePos1, SavePos2: Int64;
  Count: Int64;
  N: Integer;
begin
  if Stream1.Size<>Stream2.Size then begin
    Result := False;
    exit;
  end;

  SavePos1 := Stream1.Position;
  SavePos2 := Stream2.Position;
  Try
    Stream1.Position := 0;
    Stream2.Position := 0;

    Count := Stream1.Size;
    while Count <> 0 do begin
      N := Min(SizeOf(Buffer1), Count);
      Stream1.ReadBuffer(Buffer1, N);
      Stream2.ReadBuffer(Buffer2, N);
      if not CompareMem(@Buffer1, @Buffer2, N) then begin
        Result := False;
        exit;
      end;
      dec(Count, N);
    end;
    Result := True;
  Finally
    Stream1.Position := SavePos1;
    Stream2.Position := SavePos2;
  End;
end;


如果您希望将100MB大小的检查添加到此功能,则很明显在何处以及如何执行。

上面的例程使用堆栈分配的缓冲区。相反,您的版本在堆上分配。也许您的版本导致堆碎片。

我意识到这并不能回答您提出的直接问题。但是,它确实可以解决您的问题。我希望这证明是有用的。

关于delphi - delphi TFileStream“内存不足”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14799420/

相关文章:

delphi - 非英语语言iOS应用XE4问题

delphi - 如何获取 DBGrid 单元格的屏幕坐标

Delphi:TPanel 和文本缩进

delphi - 如何在Delphi中集中Windows异常对话框?

perl - 什么会导致 Perl 转储核心?

c - 在 C 中为结构内的指针分配和分配内存?

c++ - 对集合的键类型使用比较函数会导致运行时错误

c - C:指向结构的指针数组的指针(分配/解除分配问题)

excel - VBA 中的 .Find() 方法出现“类型不匹配”错误

azure - 无法访问azure应用程序服务中的keycloak控制台 - 脚本ssl错误