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

看到这个答案:从delphi中的文件快速读/写

一些选项是:

要搜索文件缓冲区,请参阅在流中查找给定字节序列开始位置的最佳方法- 一个答案提到了用于快速检测字节序列的Boyer-Moore 算法。

于 2013-03-27T15:47:30.257 回答
3

您将整个文件读入字符串的代码非常浪费。Pascal I/O 使用缓冲,所以我不认为这是逐字节的方面。虽然一大读会更好。主要问题将是字符串连接和连接字符串所需的极端堆分配需求,一次一个字符。

我会这样做:

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 回答