Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Delphi.doc
Скачиваний:
15
Добавлен:
19.03.2015
Размер:
176.13 Кб
Скачать

Запись строк в файл и чтение из файла

Очень часто возникают вопросы вроде такого: Пишу строку в файл, затем читаю её от-туда, в результате получаю белиберду. В качестве кода приводят что-то вроде такого:

var

Stream :tStream;

Str :AnsiString;

...

Stream.WriteBuffer(Str,SizeOf(Str)); // так пишу

...

Stream.ReadBuffer(Str,SizeOf(Str)); // так читаю

или

var

f :file;

Str :AnsiString;

...

BlockWrite(f,Str,SizeOf(Str)); // так пишу

...

BlockRead(f,Str,SizeOf(Str)); // так читаю

Естественно, поскольку переменная динамической строки - на самом деле указатель, то таким образом, записывается лишь четыре байта адреса текущего положения строки в памяти. Естественно, что при чтении этот адрес не имеет никакого смысла.

Такой способ записи/чтения приемлем только для строковых переменных типов ShortString и String[n], поскольку переменные этих типов хранят саму строку, а не указатель на неё. Более того, есть даже одно неявное удобство. Поскольку в начале таких переменных хранится и байт текущей длины строки, то он тоже записывается в файл. Поэтому, при чтении записанной таким образом строки не встает проблемы с определением её действительного размера. Однако надо понимать что таким образом Вы получаете не текстовый файл. Во первых, байт длины может принимать любые значения от 0 до 255, и не всегда будет представлять собой код печатного символа. Во вторых, если, например, строка объявлена как ShortString. То даже если она в данный момент содержит в себе строку 'abcd', в файл будет записано 256 байт. 1 байт длины, 4 байта реальной строки и 251 байт "мусора", не обязательно печатного :).

Но, вернемся к записи динамических строк. Когда ошибка становится понятной, обычно следующим шагом переделывают алгоритм записи строки, например, так:

Stream.WriteBuffer(pChar(Str)^,Length(Str)); // так пишу

или так:

BlockWrite(f, pChar(Str)^,Length(Str)); // так пишу

Ну а потом, встает естественный вопрос – а как же это прочитать? Ведь неизвестно сколько байт занимает строка, а, следовательно, и неизвестно сколько байт из файла читать. Да и размер буфера неясен. Так вот. Об этом надо позаботиться заранее, ещё когда записываешь строку. Например, записать можно так:

var

Stream :tStream;

Str :AnsiString;

Len :Longint;

...

Len := Length(Str);

Stream.WriteBuffer(Len,SizeOf(Len)); // длинна строки

Stream.WriteBuffer(pChar(Str)^,Length(Str)); // сама строка

или так:

var

f :file;

Str :AnsiString;

Len :Longint;

...

Len := Length(Str);

BlockWrite(f,Len,SizeOf(Len)); // длинна строки

BlockWrite(f,pChar(Str)^,Length(Str)); // сама строка

Тогда, можно будет прочитать вот так:

Stream.ReadBuffer(Len,SizeOf(Len)); // длинна строки

SetLength(Str,Len); // выделение памяти под строку

Stream.ReadBuffer(pChar(Str)^,Len); // чтение строки

или так:

BlockRead(f,Len,SizeOf(Len)); // длинна строки

SetLength(Str,Len); // выделение памяти под строку

BlockRead(f,pChar(Str)^,Len); // чтение строки

Что, сложно? Ну, за возможность хранить строки длинной >255 символов приходится платить.

Если же тебе достаточно и 255 символов, то используй ShortString, или String[n].

Есть еще одно, на мой взгляд, замечание. Если Вы обратили внимание на тип переменной Len в моем примере, то возможно у Вас возник вопрос: А почему LongInt, а не Integer? Жаль если у Вас вопрос не возник – либо вы все знаете, либо ничего :). Для остальных поясню: дело в том, что тип LongInt фундаментальный тип, размер которого (4 байта) не будет меняться в последующих версиях Delphi. А тип Integer, это универсальный тип, размерность которого может меняться от версии к версии. Например, для 64-разрядных компьютеров он наверняка "вырастет" до 8-ми байт (64 бита). Лично мне, хочется, что бы файлы данных записанные моей старой версией программы могли быть нормально прочитаны более поздними версиями, возможно скомпилированными уже под 64-разрядной OS.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]