Чтение последней строки большого Unicode-файла в Delphi
Иногда в процессе разработки программ на языке Delphi возникает необходимость чтения последней строки из большого текстовых файла. Однако стандартные подходы, такие как использование TStringList, могут привести к ошибке "превышения памяти". В таком случае можно использовать методы прямого доступа к файлу, но это может быть связано с проблемами при работе с файлами в кодировке Unicode.
Проблема:
При работе с большими текстовыми файлами может возникнуть задача чтения последней строки для извлечения временной метки. Использование TStringList может привести к ошибке "Out of memory", а попытки использовать Seek и BlockRead могут привести к тому, что в буфере окажутся нечитаемые символы. Это может быть связано с особенностями работы с Unicode.
Решение:
Для решения данной проблемы можно использовать класс TFileStream из Delphi, который позволяет работать с файлами, используя более современные и мощные возможности. Ниже представлен пример функции, которая читает последнюю строку файла:
uses System.IOUtils, System.Math, System.Classes;
type
FileChar = AnsiChar; FileString = AnsiString; // для не-Unicode файлов
// type FileChar = WideChar; FileString = UnicodeString; // для UTF16 и UCS-2 файлов
const FileCharSize = SizeOf(FileChar);
// ...
function ReadLastLine(const FileName: String): FileString; overload;
// ...
const
PageSize = 4*1024; // минимальный размер блока чтения
// ...
function ReadLastLine(const Lines: TStringDynArray): FileString; overload;
var
i: integer;
begin
// ...
end;
function FindLastLine(buffer: TArray<FileChar>; const OldRead: Integer;
const LastChunk: Boolean; out Line: FileString): boolean;
var
i, tailCRLF: integer; c: FileChar;
begin
// ...
end;
function ReadLastLine(const FileName: String): FileString; overload;
var
Buffer, tmp: TArray<FileChar>;
FS: TFileStream; FSize, NewPos: Int64;
OldRead, NewLen: Integer; EndOfFile: boolean;
begin
// ...
Result := '';
FS := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
FSize := FS.Size;
// ...
if FSize <= PageSize then
begin
// ...
Result := ReadLastLine(TFile.ReadAllLines(FileName, TEncoding.ANSI));
// или TEncoding.UTF16
exit;
end;
// ...
SetLength(Buffer, PageSize div FileCharSize);
OldRead := 0;
repeat
// ...
NewPos := FSize - Length(Buffer) * FileCharSize;
// ...
FS.Position := NewPos;
// ...
if FindLastLine(Buffer, OldRead, EndOfFile, Result) then
exit;
// ...
tmp := Buffer; Buffer := nil;
// ...
SetLength(Buffer, NewLen);
// ...
until EndOfFile;
finally
FS.Free;
end;
end;
Особенности решения:
Использование TFileStream позволяет работать с большими файлами, не загружая их целиком в память.
Функция ReadLastLine читает файл большими блоками, начиная с конца файла, что позволяет быстро найти последнюю строку.
Функция учитывает различные символы конца строки (CR, LF, CRLF).
При работе с Unicode файлами важно учитывать особенности кодировки, например, что символы Unicode занимают два байта.
Альтернативные подходы:
Использование памяти, отображённой на файл (Memory-Mapped Files, MMF), может упростить чтение последней строки, но требует более глубокого понимания работы с памятью и файловой системой.
Необходимо тщательно тестировать код на различных типах файлов, чтобы убедиться в его корректности.
Использование представленного кода позволит эффективно читать последнюю строку из больших текстовых файлов в Delphi, работая с файлами в кодировке Unicode.
Описание: Необходимо разработать метод для чтения последней строки в большом файле Unicode в Delphi, избегая загрузки всего файла в память.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.