4

バイナリ ファイル (2.5 MB) があり、次のバイト シーケンスの位置を見つけたいと考えています: CD 09 D9 F5。次に、この位置の後にデータを書き込み、古いデータ (4 KB) をゼロで上書きします。

これが今のやり方ですが、少し遅いです。

ProcessFile(dataToWrite: string);
var
  fileContent: string;
  f: file of char;
  c: char;
  n, i, startIndex, endIndex: integer;
begin
  AssignFile(f, 'file.bin');
  reset(f);
  n := FileSize(f);
  while n > 0 do
  begin
    Read(f, c);
    fileContent := fileContent + c;
    dec(n);
  end;
  CloseFile(f);

  startindex := Pos(Char($CD)+Char($09)+Char($D9)+Char($F5), fileContent) + 4;
  endIndex := startIndex + 4088;

  Seek(f, startIndex);

  for i := 1 to length(dataToWrite) do
    Write(f, dataToWrite[i]);

  c := #0;
  while (i < endIndex) do
  begin
    Write(f, c); inc(i);
  end;

  CloseFile(f);
end;
4

2 に答える 2

6

この回答を参照してください:デルファイのファイルからの高速読み取り/書き込み

いくつかのオプションは次のとおりです。

ファイル バッファを検索するには、特定のバイト シーケンスが開始するストリーム内の位置を見つけるための最良の方法を参照てください。

于 2013-03-27T15:47:30.257 に答える
3

ファイル全体を文字列に読み込むコードは非常に無駄です。Pascal I/O はバッファリングを使用するので、特にバイト単位の側面ではないと思います。1回の大きな読書の方が良いでしょうが。主な問題は、文字列の連結と、一度に 1 文字ずつ文字列を連結するために必要な極端なヒープ割り当て要求です。

私は次のようにします:

function LoadFileIntoString(const FileName: string): string;
var
  Stream: TFileStream;
begin
  Stream := TFileStream.Create(FileName, fmOpenRead);
  try
    SetLength(Result, Stream.Size);//one single heap allocation
    Stream.ReadBuffer(Pointer(Result)^, Length(Result));
  finally
    Stream.Free;
  end;
end;

それだけでも大きな違いになるはずです。ファイルの書き込みに関しては、文字列を同様に使用すると、はるかに高速になります。あなたのコードの書き込み部分を解読しようとはしていません。新しいデータの書き込みとゼロのブロックの書き込みは、できるだけ少ない数の個別の書き込みにまとめて行う必要があります。

ファイルに対して非常に小さなブロックを読み書きする必要があることがわかった場合は、バッファリングされたファイルストリームを提供します:バッファリングされたファイル (ディスクアクセスを高速化するため)

コードをさらに最適化して、ファイルの一部のみを読み取り、ターゲットが見つかるまで検索することができます。そのようにしてファイル全体を読み取ることを回避できる場合があります。ただし、これらの変更により、十分な違いが生じると思います。

于 2013-03-27T18:14:45.820 に答える