2013-03-27 3 views
4

У меня есть двоичный файл (2.5 MB), и я хочу найти позицию этой последовательности байтов: CD 09 D9 F5. Затем я хочу записать некоторые данные после этой позиции, а также перезаписать старые данные (4 КБ) нулями.Delphi Как быстрее искать в двоичном файле?

Вот как я это делаю сейчас, но это немного медленно.

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

Какая часть кода медленная? Вы проводили тайминги? Как вы даже знаете, что это медленно? Какова скорость, и чего вы ожидаете достичь? –

+5

Очевидно, что чтение и запись файла char-by-char происходит медленно. По крайней мере, получить данные в буфер более крупными кусками (см. BlockRead). – OnTheFly

+0

@DavidHeffernan, Да, часть, где он ищет позицию последовательности, медленная. Теперь это занимает около 15 секунд для 5 файлов, я хочу, чтобы оно составляло не более 1-3 секунд. Если я прокомментирую это и просто поставлю StartIndex к 9999, например, тогда это мгновенно. Я думаю, что это не лучшее решение для чтения байта содержимого файла байтом в виде символов + скопировать его в строку. – AlexP11223

ответ

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; 

Это само по себе должно сделать большую разницу. Когда дело доходит до написания файла, подобное использование строк будет намного быстрее. Я не пытался расшифровать написанную часть вашего кода. Написание новых данных, а блок нулей снова должен быть доведен до максимально возможного количества отдельных записей.

Если вы когда-либо обнаружите, что вам нужно читать или писать очень маленькие блоки в файл, я предлагаю вам свои буферизованные потоки файлов: Buffered files (for faster disk access).

Код может быть оптимизирован далее для чтения только части файла и поиска, пока вы не найдете цель. Возможно, вы сможете не читать весь файл таким образом. Тем не менее, я подозреваю, что эти изменения сделают достаточно разницы.

6

Смотрите этот ответ: Fast read/write from file in delphi

Некоторые опции:

Чтобы найти файл-буфер, см. Best way to find position in the Stream where given byte sequence starts - в одном ответе упоминается Boyer-Moore algorithm для быстрого обнаружения последовательности байтов.

+0

Я бы просто прочитал блок, сканировал его на первый байт, оценил остальное, закоротив, когда это необходимо. Работа с началом последовательности, появляющейся в конце блока, кажется здесь наиболее очевидным краевым условием. –

Смежные вопросы