Добрый день, Уважаемые жители королевства.
Подскажите, пожалуйста, как правильно записать строку в поток TFileStream и, соответственно, прочитать в Delphi 11 Alexandria.
Вроде, все просто.
Записываем:
procedure TForm1.Button1Click(Sender: TObject);
var
fs: TFileStream;
S: String;
d: Integer;
begin
S := 'Мой какой-то определенный текст, который может быть разной длины и все такое прочее';
fs := TFileStream.Create('c:\MyFile.dat', fmCreate or fmOpenWrite);
d := Length(S) * SizeOf(Char); //AnsiChar - без разницы.
fs.WriteBuffer(d, SizeOf(d)); fs.WriteBuffer(S[1], d);
fs.Free;
end;
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
12-12-2023 14:32
Наверное, самое простое и быстрое решение, это заменить SetLength(S, d); на SetLength(S, d div siseof(Char)); ???
Это скорее предположение, чем ответ. Поправьте если я ошибаюсь.
1. В Delphi 7, структура строки в памяти походила на байтовый динамический массив и описывалась структурой System.PStrRec. Другими словами, кроме данных самой строки, в памяти хранились значения количества ссылок и размер строки в байтах (там правда есть ещё один, несущественный для нас, параметр capacity). При сохранении (восстановлении) строки в поток (из потока), практически приходилось работать с этой структурой. Значение "количества ссылок" нас не интересовало, а вот "значение длины" и "содержание строки", записывались (восстанавливались) раздельно.
Поэтому для считывания и записи в поток строки можно было использовать такие процедуры.
1) Первый способ записи строки в поток (через указатель).
function TfvMain.StrLoadToStream(aStream: TStream): string;
var nSize :integer;
begin
// -считывание из потока
FStream.ReadBuffer(nSize, SizeOf(nSize));
if nSize > 0
then begin
SetLength(Result, nSize);
FStream.ReadBuffer(Result[1], nSize);
end
else
Result := '';
end;
procedure TfvMain.StrSaveToStream(aStream: TStream; const aStr: string);
var nSize :integer;
begin
// -запись в поток
nSize := Length(aStr);
FStream.WriteBuffer(nSize, SizeOf(nSize));
if nSize > 0
then FStream.WriteBuffer(aStr[1], nSize);
end;
2) Второй способ записи строки в поток (через TStringStream).
function TfvMain.StrLoadToStream2(aStream: TStream): string;
var
nSize :integer;
wStream :TStringStream;
begin
// -считывание из потока
FStream.ReadBuffer(nSize, SizeOf(nSize));
Result := '';
if nSize > 0
then begin
wStream := TStringStream.Create('');
try
wStream.CopyFrom(FStream, nSize);
Result := wStream.DataString;
finally
wStream.Free;
end;
end;
end;
Попутный вопрос. А интересно, класс TStringStream добавлен в vcl ради вот этого CopyFrom() одного метода?
2. В Delpih XE (смотрю по rtl версии 10.2) структура System.PStrRec несколько расширилась.
StrRec = packed record
{$IF defined(CPU64BITS)}
_Padding: Integer; // Make 16 byte align for payload..
{$ENDIF}
codePage: Word;
elemSize: Word;
refCnt: Integer;
length: Integer;
end;
Добавилось два параметра: "кодировка" и "размер элемента".
Очевидно, что для сохранения строки в поток нужно, кроме самих "данных строки", придётся сохранить остальные три значения (codePage, elemSize, length). Для получения этих значений можно использовать функции StringCodePage, StringElementSize, Length. А для установки - SetCodePage (она же установит elemSize), SetLength. Важно не забыть, что функции Length и SetLength оперируют количеством символов, а не размером в байтах. (О чём уже упомянул Geo.)
Предположу, что с учётом этих поправок будут работать процедуры 1) и 2).
Вы считываете из файла Integer, который назначаете длиной строки, но записываете в файл вы не длину строки, а количество байт, занимаемых строкой. То есть для WideString у вас длина строки будет в 2 раза больше чем количество символов в сохранённой строке. Естественно, во второй половине будет болтаться произвольный мусор, который был в памяти, выделенной под строку.
Кстати, сразу уточняющий вопрос... Когда вы строку из файла прочитали, в первой половине строки правильное значение? Соответствует тому, что было сохранено?
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.