首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >delphi TFileStream“内存不足”

delphi TFileStream“内存不足”
EN

Stack Overflow用户
提问于 2013-02-10 23:41:53
回答 1查看 2.4K关注 0票数 1

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

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

读取的数据块有多大似乎并不重要,重要的似乎是导致错误消息的调用次数。

代码是我编写的一个函数,每当程序遇到两个需要比较的文件时,它就会在其他地方被调用(因为我不会详细介绍的原因,可能是40或50个不同的文件对)。无论是以小块形式读取的单个文件,还是完整读取的多个文件,都会出现“内存不足”错误。似乎是调用的数量是错误的决定因素。

虽然我意识到可能有比下面所示更好的方法来实现文件的比较,但我真正想知道的是,导致内存问题的TFileStream和/或SetLength调用的使用出了什么问题。我尝试在每次调用后释放内存(如代码所示),但似乎没有什么不同。

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

代码语言:javascript
复制
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 }
EN

回答 1

Stack Overflow用户

发布于 2013-02-10 23:49:59

这个例程似乎比它需要的复杂得多。我提供了一个比较流的例程,而不是尝试调试它。

代码语言:javascript
复制
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大小检查添加到此函数中,那么在哪里以及如何执行该操作是显而易见的。

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

我意识到这并没有回答你提出的直接问题。然而,它确实解决了你的问题。我希望这被证明是有用的。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14799420

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档