Delphi 7. Занятие 2_4.
Содержание
Сохранение данных в нетипизированный файл.
Прежде, чем начать разговор о том, как записывать/читать в delphi в нетипизированный файл, сделаем ещё несколько замечаний по поводу типизированных файлов.
Delphi stream
Все предварительные замечания были сделаны постольку, поскольку для работы с нетипизированными файлами удобно применять класс TFileStream.
Применение этого класса значительно упрощает код, который необходимо написать для работы с нетипизированным файлом.
Кроме того, этот класс позволяет напрямую читать отдельные байты непосредственно из файла на диске.
Воспользуемся эти классом, чтобы создать, записать и затем прочитать файл.
Объявляем переменную типа TFileStream:
FS: TFileStream;
С помощью класса TFileStream инициализируется переменная FS и создаётся новый файл:
Const p=’D:\MyFile2.text’;
FS := TFileStream.Create(p, fmCreate);
Говорят, что мы создали объект FS класса TFileStream . Этот объект называется «потоком».
Собственно говоря, поток — это область динамической памяти, куда можно скопировать данные из файла.
Обратите внимание на параметр fmCreate. Он предписывает процедуре «Create» (конструктору) создать на диске файл.
После создания на диске файл оказывается связанным с потоком, он пуст и «открыт», хотя никаких манипуляций с ним пока производить нельзя.
Так как больше ни на что созданный таким образом поток не способен, его надо закрыть:
FS.Free;
Запись данных в поток (в файл, связанный с потоком)
Чтобы создать поток для записи данных в файл его надо пересоздать (переоткрыть):
FS := TFileStream.Create(p, fmOpenWrite or fmShareExclusive);
Теперь можно использовать методы (процедуры) потока для записи данных в файл.
Будем записывать строки, хранящиеся в компоненте memo1:
Опишем переменные: (обратите внимание, что в отличие от других языков, строчными или прописными буквами написан идентификатор — значения не имеет. FS и fs – одна и та же переменная).
implementation
var fs:TFileStream;
n, pos, len, Iss, size:int64;
s, ss:string;
ch:char;
Полностью процедура имеет вид:
procedure TForm1.Button1Click(Sender: TObject);
var I,ii:integer;
begin
FS := TFileStream.Create(p, fmCreate); //создаём файл
FS.Free; //закрываем поток
FS := TFileStream.Create(p, fmOpenWrite or fmShareExclusive); //открываем поток для записи.
n:= memo1.Lines.Count-1; //определяем количество строк в memo1 и уменьшаем на 1 (так как отсчет строк ведётся от 0).
for I := 0 to n do //проходим в циклк все строки
begin
s:= memo1.Lines.Strings[I]; //читаем из memo1 строку I.
len:= Length(s) ; //определяем длину строки (количество символов в строке)
Iss:=SizeOf(LongInt) ; //Это функция возвращает количество байт, выделенных для хранения значения переменной. Для LongInt отводится 4 байта. Для типа Int64 требуется 8 байт.
FS.Write(len,Iss); //записываем число (именно число, а не его строковое представление! Число равно $3, а представление числа ‘3’ соответствует номеру расположения знака «3» в кодовой таблице символов и равно $33 (51 в десятичном счислении). Знак $ означает запись числа в шестнадцатеричном счислении.
Под число будет отведено столько байт на диске, сколько требуется для представления числа типа Int64 (так как в переменной Iss содержится значение 4, то на диске будет зарезервировано 4 байта).
Для чего надо записывать эту длину, будет ясно при чтении данных из потока.
FS.Write(s[1], len); //записываем len символов из строки s.
Общий формат процедуры Write:
FS.Write(переменная_содержимое_которой_записывается_на диск, количество_байт_которое_приказываем_отвести_на_диске_под_запись_значения);
Здесь надо быть осторожным, так как ошибочное указание количества байт приведет к неверной записи содержимого записываемой переменной.
Если мы записываем символ, то надо отвести ровно 1 байт, если целое число типа LongInt, то ровно 4 байта, если записываем строку — то указывается столько байт, сколько символов содержится в строке.
Замечание. Процедура Write начинает записывать содержимое переменной, начиная с нулевого байта. Но, как мы говорили ранее, в строке первые 14 байт заняты служебной информацией. Нотация s[1] указывает, что запись надо начинать с байта, содержащего первый символ. Этим самым мы как бы отрезаем ведущие байты.
end;//for конец тела цикла
FS.Free; //закрываем поток (при этом закрывается и связанный с ним файл)
end; //конец процедуры
delphi чтение из нетипизированного файла через поток.
Теперь организуем чтение из потока (из файла, связанного с потоком).
procedure TForm1.Button4Click(Sender: Tobject);
var I,ii:integer;
begin
FS := TFileStream.Create(p, fmOpenRead or fmShareExclusive); //открываем поток для чтения.
size:=fs.Size; //определяем размер потока (размер связанного с потоком файла) в байтах с помощью метода Size объекта fs .
Repeat //цикл с постусловием
fs.Read(len,Iss); //читаем Iss байт. Значение, записанное в этих байтах, интерпретируется в соответствие с типом переменной len и записывается в неё.
После чтения len указатель в потоке переместится на len позиций и установится на первом символе строки.
Ss:=»; //обнуляем переменную
for ii:=1 to len do //for цикл len раз. (как мы помним, len равно длине строки, записаной на диске непосредственно за значением len).
begin
fs.Read(ch,1); //читаем символ
ss:=ss+ch; //формируем строку из символов
end; //for после завершения for указатель в потоке сместится на количество прочитанных символов и установится на первом байте числа (под которое было отведено 4 байта).
Распределение байт для первой строки:
memo2.Lines.Append(ss); //заполнение memo2
pos:=fs.Position; //читаем положение курсора в потоке (в файле)
until pos>=size; //как только значение pos станет больше или равно размеру файла size, выполнение цикла завершится.
FS.Free; //закрываем поток
end;
Работа с нетипизированными файлами — не самое простое занятие. Но в некоторых случаях бывает очень эффективной, а порой и незаменимой.
Заключение.
Для работы с файлом познакомились с функцией FileSize(ф.п.) — определение размера файла; с функцией filePos(ф.п.); функцией seek(ф.п., ном.зап) . Создали форму для примера работы с типизированным файлом.
В этом занятии мы познакомились с новым компонентом TbitBtn. Рассмотрели объявление нетипицированногофайла var vMyFile:File; . Использовали для отладки кода останов.
Более подробно рассмотрели особенности формирования строк, символы перевода строки и возврата каретки.
Самое основное — рассмотрели приёмы работы с файлом через поток типа TStreamFile. Познакомились более подробно с понятием «объект» и «класс».
Рассмотрели новый тип данных «запись». Создали код для записи в поток данных и для их считывания из потока.
Глоссарий.
Позиционирование указателя типизированного файла seek(ф.п., ном.зап) .
Функция определения размера файла FileSize(ф.п.).
Определение позиции файлового указателя filePos(ф.п.).
Компонет TBitBtn
Объявление нетипизированногофайла var vMyFile:File;
Понятие «останов» при отладке программы.
Символы конца строки и перевода каретки #13#10
Понятие «поток».
Объект для работы с нетипизированным файлом TFileStream.
Понятие «структурированные типы данных».
Тип данных запись: record … end;
Терминальныq нуль.
Понятие «класс»
Объявление переменной типа «поток» FS: TFileStream;
Инициация потоковой переменной и создание файла через конструктор, принадлежащий типу TFileStream : fs:=TFileStream.Create(p,fmCreate);
Создание потока для записи в файл:
FS := TFileStream.Create(p, fmOpenWrite or fmShareExclusive);
Запись данных в поток (в файл, связанный с потоком)
FS.Write(s[1], len);
Создание потока для чтения из файла: FS := TFileStream.Create(p, fmOpenRead or fmShareExclusive);
Чтение данных из потока (в файл, связанный с потоком)
fs.Read(ch,1);
Рассмотрели распределение байт для первой строки.