- •Строковые типы в Delphi. Особенности реализации и использования
- •Какие строковые типы существуют в Delphi, и чем они отличаются друг от друга?
- •Так как они устроены?
- •Как же это происходит?
- •Преобразование строк из одного типа в другой
- •Функции для работы со строками, о которых многие часто забывают, или вовсе не знают
- •If AnsiMatchText(YouName,['Вася','Петя','Гриша']) then
- •Запись строк в файл и чтение из файла
- •Использование строк в записях
- •Использование строк в качестве параметров и результатов функций размещенных в dll.
Запись строк в файл и чтение из файла
Очень часто возникают вопросы вроде такого: Пишу строку в файл, затем читаю её от-туда, в результате получаю белиберду. В качестве кода приводят что-то вроде такого:
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.