Работа с TMemoryStream в Delphi: корректное чтение и запись строк Unicode
В данной статье мы рассмотрим проблему, с которой сталкиваются разработчики при работе с TMemoryStream в Delphi, особенно при чтении и записи строк Unicode. Эта проблема часто выражается в том, что после чтения данных из TMemoryStream строки содержат случайные значения, а не ожидаемые данные. Мы постараемся объяснить причину возникновения этой ошибки и предложим корректное решение.
Проблема
Разработчики часто сталкиваются с трудностями при записи и последующем чтении строк из TMemoryStream в Delphi. Пример кода, представленный ниже, демонстрирует типичную ситуацию, когда перед сохранением данных в файл строка содержит ожидаемое значение, но после загрузки данных из файла строка оказывается некорректной.
procedure SaveData(FileName: TFileName);
var
MemStr: TMemoryStream;
Title: String;
begin
MemStr:= TMemoryStream.Create;
try
MemStr.Seek(0, soFromBeginning);
WriteStreamStr(MemStr, Title);
MemStr.SaveToFile(FileName);
finally
MemStr.Free;
end;
end;
procedure LoadData(FileName: TFileName);
var
MemStr: TMemoryStream;
Title: String;
begin
MemStr:= TMemoryStream.Create;
try
MemStr.LoadFromFile(FileName);
MemStr.Seek(0, soFromBeginning);
Title := ReadStreamStr(MemStr);
finally
MemStr.Free;
end;
end;
procedure WriteStreamStr(Stream: TStream; Str: string);
var
StrLen: Integer;
begin
StrLen := Length(Str);
WriteStreamInt(Stream, StrLen);
if StrLen > 0 then
Stream.Write(Str[1], StrLen);
end;
function ReadStreamStr(Stream: TStream): string;
var
LenStr: Integer;
begin
Result := '';
LenStr := ReadStreamInt(Stream);
SetLength(Result, LenStr);
Stream.Read(Result[1], LenStr);
end;
Описание проблемы с Unicode
Проблема, которая возникает, связана с тем, как в Delphi представляются строки Unicode. В коде, представленном выше, используется Stream.Write для записи строки в TMemoryStream, что делается на основе предположения, что каждый символ строки занимает один байт. Это верно для строк ANSI, но не для строк Unicode, где каждый символ занимает два байта (если рассматривать стандартный размер символа в Delphi, который SizeOf(Char) равен 2).
Решение
Исправление кода состоит в том, чтобы изменить количество байтов, передаваемых функции Stream.Write, на StrLen * SizeOf(Char). Это гарантирует, что будет записано корректное количество байтов для строки Unicode. Аналогично, при чтении данных из потока, необходимо использовать SizeOf(Char) для корректного чтения строки.
procedure WriteStreamStr(Stream: TStream; Str: string);
var
StrLen: Integer;
begin
StrLen := Length(Str);
WriteStreamInt(Stream, StrLen);
if StrLen > 0 then
Stream.Write(Str[1], StrLen * SizeOf(Str[1]));
end;
function ReadStreamStr(Stream: TStream): string;
var
LenStr: Integer;
begin
Result := '';
LenStr := ReadStreamInt(Stream);
SetLength(Result, LenStr * SizeOf(Char)); // Учитываем размер символа
Stream.Read(Result[1], LenStr * SizeOf(Char));
end;
Альтернативные подходы
Перед тем как применить исправления, стоит рассмотреть альтернативные подходы, такие как использование TStringStream или методов TStrings.SaveToStream и LoadFromStream. Это может быть более простым и эффективным решением, особенно если требуется работать только со строками.
Заключение
В данной статье мы рассмотрели типичную проблему, связанную с некорректной работой с TMemoryStream и строками Unicode в Delphi. Предложенное решение заключается в корректировке количества байтов, передаваемых при записи и чтении данных, с учетом размера символа в строке. Это позволит избежать ошибок при работе с Unicode-строками в TMemoryStream.
Статья посвящена решению проблемы корректного чтения и записи строк Unicode с использованием `TMemoryStream` в Delphi, где рассмотрена ошибка, связанная с неправильным учетом размера символов Unicode при работе с потоками.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.