簡體   English   中英

delphi TFileStream“內存不足”

[英]delphi TFileStream “out of memory”

我在使用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大小的檢查添加到此功能,則很明顯在何處以及如何執行。

上面的例程使用堆棧分配的緩沖區。 相反,您的版本在堆上分配。 也許您的版本導致堆碎片。

我意識到這並不能回答您提出的直接問題。 但是,它確實可以解決您的問題。 我希望這證明是有用的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM