Быстрое чтение/запись из файла в Делфи
я загружаю файл в массив в двоичной форме, это занимает некоторое время есть ли лучший, более быстрый и эффективный способ сделать это. я использую аналогичный метод для записи обратно в файл.
procedure openfile(fname:string);
var
myfile: file;
filesizevalue,i:integer;
begin
assignfile(myfile,fname);
filesizevalue:=GetFileSize(fname); //my method
SetLength(dataarray, filesizevalue);
i:=0;
Reset(myFile, 1);
while not Eof(myFile) do
begin
BlockRead(myfile,dataarray[i], 1);
i:=i+1;
end;
CloseFile(myfile);
end;
6 ответов
обычно вы не должны читать файлы байт за байтом. Используйте BlockRead с большим значением (512 или 1024 часто лучше всего) и используйте его возвращаемое значение, чтобы узнать, сколько байтов было прочитано.
Если размер не слишком велик (и ваше использование SetLength, похоже, поддерживает это), вы также можете использовать один вызов BlockRead, читающий полный файл сразу. Итак, изменив свой подход, это будет:
AssignFile(myfile,fname);
filesizevalue := GetFileSize(fname);
Reset(myFile, 1);
SetLength(dataarray, filesizevalue);
BlockRead(myFile, dataarray[0], filesizevalue);
CloseFile(myfile);
возможно, вы также можете изменить процедуру на логическую функцию с именем OpenAndReadFile и возвращает false, если файл не удалось открыть или прочитать.
Если вы действительно хотите быстро прочитать двоичный файл, пусть windows беспокоится о буферизации ; -) с помощью Сопоставленные С Памятью Файлы. Используя это, вы можете просто сопоставить файл с местоположением памяти и прочитать его как массив.
ваша функция станет:
procedure openfile(fname:string);
var
InputFile: TMappedFile;
begin
InputFile := TMappedFile.Create;
try
InputFile.MapFile(fname);
SetLength(dataarray, InputFile.Size);
Move(PByteArray(InputFile.Content)[0], Result[0], InputFile.Size);
finally
InputFile.Free;
end;
end;
но я бы предложил не использовать глобальную переменную dataarray
, но либо передайте его как var в параметре, либо используйте функцию, которая возвращает результирующий массив.
procedure ReadBytesFromFile(const AFileName : String; var ADestination : TByteArray);
var
InputFile : TMappedFile;
begin
InputFile := TMappedFile.Create;
try
InputFile.MapFile(AFileName);
SetLength(ADestination, InputFile.Size);
Move(PByteArray(InputFile.Content)[0], ADestination[0], InputFile.Size);
finally
InputFile.Free;
end;
end;
В TMappedFile из моей статьи Быстрое чтение файлов с помощью карты памяти, эта статья также содержит пример того, как использовать его для более "продвинутых" двоичных файлов.
Это зависит от формата файла. Если он состоит из нескольких одинаковых записей, вы можете решить создать файл этого типа записи.
например:
type
TMyRecord = record
fieldA: integer;
..
end;
TMyFile = file of TMyRecord;
const
cBufLen = 100 * sizeof(TMyRecord);
var
file: TMyFile;
i : Integer;
begin
AssignFile(file, filename);
Reset(file);
i := 0;
try
while not Eof(file) do begin
BlockRead(file, dataarray[i], cBufLen);
Inc(i, cBufLen);
end;
finally
CloseFile(file);
end;
end;
Если это достаточно длинный файл, чтение которого таким образом занимает заметное количество времени, я бы использовал поток. Чтение блока будет намного быстрее, и нет никаких петель, о которых нужно беспокоиться. Что-то вроде этого:--3-->
procedure openfile(fname:string);
var
myfile: TFileStream;
filesizevalue:integer;
begin
filesizevalue:=GetFileSize(fname); //my method
SetLength(dataarray, filesizevalue);
myFile := TFileStream.Create(fname);
try
myFile.seek(0, soFromBeginning);
myFile.ReadBuffer(dataarray[0], filesizevalue);
finally
myFile.free;
end;
end;
из вашего кода видно, что ваш размер записи составляет 1 байт. Если нет, то измените строку читать:
myFile.ReadBuffer(dataarray[0], filesizevalue * SIZE);
или что-то подобное.
Поиск буферизованного потомка TStream. Это сделает ваш код намного быстрее, так как чтение диска выполняется быстро, но вы можете легко выполнить цикл через буфер. Есть разные О, или вы можете написать свой собственный.
Если вы чувствуете себя очень растерянным, вы можете полностью обойти Win32 и вызвать функцию NT Native API ZwOpenFile (), которая в моем неофициальном тестировании немного сбривается. В противном случае, я бы использовал решение сопоставленного файла памяти Дэви выше.