Чтение и запись файлов в delphi

Delphi 7. Занятие 2_3.

Сохранение данных в типизированный файл.

Предварительные замечания.

Прежде, чем начать разговор о нетипизиованных файлах, сделаем ещё несколько замечаний по поводу записи в типизированный файл в delphi.

Они будут необходимы нам в дальнейшем при работе с нетипизированными файлами.

Позиционирование указателя типизированного файла.

Типизированный файл, в отличие от текстового файла, позволяет прочитать отдельную запись. Так как длина всех записей одинакова, их можно пронумеровать и обращаться к записи по номеру, наподобие одномерного массива.

Для обращения к записи по её номеру существует процедура позиционирования:

seek(файловая_переменная, номер_записи) //помним, что отсчет ведутся от 0)

Создадим файл для хранения целых чисел. Запишем в него 5 значений. Проконтролируем записанные значения чтением из файла и отображение их в memo.

Определим размер файла функцией FileSize(ф.п.).

Затем установим указатель файла в четвёртую позицию (то есть номер_записи=3).

Изменим значение записи в этой позиции и вновь проконтролируем результат.

Для решения задачи подготовим форму:

типизированный файл в delphi

Воспользуемся полученной информацией и ещё раз посмотрим, как в delphi записать в файл данные фиксированной длины и какие процедуры и функции для работы с файлами нам для этого понадобятся.

Создадим обработчики событий для первой и второй кнопок:

implementation

{$R *.dfm}

var vFileInt:File Of Integer; // создаём переменную для ссылки на типизированный файл

const name=’d:\file1.int‘; //путь доступа к файлу

procedure TForm1.Button1Click(Sender: TObject);

var i,j:integer;

s:string;

begin

assignFile(vFileInt,name);

rewrite(vFileInt); //создаём файл

//

j:=filePos(vFileInt); //контролируем положение указателя файла

edit2.Text:=intToStr(j);

//

for i:=1 to 5 do

begin

j:=i*100;

write(vFileInt,j); //формируем значения и записываем их в файл.

end;

//

j:=filePos(vFileInt); //опять контролируем положение указателя в файле

edit3.Text:=intToStr(j);

//

j:=fileSize(vFileInt); //проверяем размер файла (количество записей)

edit1.Text:=intToStr(j);

reset(vFileInt); //переоткрываем файл. При этом указатель файла устанавливается на 0.

form1.Memo1.Lines.Clear;

while not EOF(vFileInt) do

begin

read(vFileInt,j); //читаем файл и прочитанные значения отображаем в memo.

s:=inttostr(j);

form1.Memo1.Lines.Append(s);

end;

closeFile(vFileInt);

end;

Форма после нажатия на первую кнопку:

чтение и запись файлов в delphi

procedure TForm1.Button2Click(Sender: TObject);

var j:integer; s:string;

begin

assignFile(vFileInt,name);

reset(vFileInt);

form1.Memo1.Lines.Clear;

seek(vFileInt,3); //устанавливаем указатель файла в четвёртую позицию (0,1,2,3)

j:=99;

write(vFileInt,j); //перезаписываем четвёртое значение

j:=filePos(vFileInt); //отображаем положение указателя файла после перезаписи.

edit4.Text:=intToStr(j);

reset(vFileInt);

//

while not EOF(vFileInt) do

begin

read(vFileInt,j); //читаем и отображаем файл

s:=inttostr(j);

form1.Memo1.Lines.Append(s);

end;

closeFile(vFileInt);

end;

Форма после нажатия на вторую кнопку:

чтение и запись файлов в delphi

Компонент TBitBtn

Продолжим знакомиться с компонентами. На вкладке Additional находится компонент TbitBtn.

Это кнопка с расширенным набором свойств.

Познакомимся с некоторыми из них, которые будут важны в данном занятии.

Если обычная кнопка TButton имеет минимальные возможности по формированию своего внешнего вида, то у TbitBtn таких возможностей гораздо больше.

Для записи в поток подготовим кнопу типа TbitBtn и настроим её так, чтобы она имела в конечном итоге вид:

типизированный файл в delphi

Как видно из рисунка, на кнопке появилась пиктограмма (красный кружок), Название кнопки выведено в трёх строках. Изменён цвет шрифта.

Для отображения названия кнопки в нескольких строках посмотрим, как хранятся строки в компоненте memo.

В окне текст отображается в виде отдельных строк. А в свойстве Memo1.Text он хранится в виде:

типизированный файл в delphi

Здесь мы видим наличие служебных символов #$D И #$A. Это кодировка двух служебных символов в таблице символов в шестнадцатеричном виде. В десятичном виде это: #13 и #10. При выводе в компонент строка читается посимвольно и выводится буква за буквой.

Встретив символ #13 (он называется «перевод каретки») вывод следующего символа будет со следующей строки с текущей позиции. Получится что-то типа «лесенки».

Чтобы перейти в начало строки, служит символ #10.

В Object Inspector нельзя добиться вставки этих служебных символов в строку. Они будут воспроизведены как простой текст.

Чтобы служебные символы сыграли свою роль, надо отдельно сформировать строку с их присутствием и записать в свойство Caption.

Удобнее всего это сделать в обработчике создания формы:

procedure TForm1.FormCreate(Sender: TObject);

begin

form1.bitbtn1.Caption:= ‘Создать нетипизированный файл’ + #13#10 + ‘Записать’+ #13#10 +’Отобразить в Memo’;

end;

Цвет символов можно изменить, раскрыв свойство Font, нажав на «+». В выпадающем списке Color можно выбрать нужный цвет символов.

Как видно на рисунке, для кнопки можно организовать подсказку. Для этого надо заполнить свойство Hint (в нашем случае там написано «подсказка») и разрешить её отображать (выставить свойство ShowHint в true).

И наконец, на кнопке отображена небольшая пиктограмма. Она подготавливается заранее в текстовом редакторе и загружается через свойcтво Glyph).

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

Простые и структурированные типы данных.

Под переменные стандартных типов отводится оговоренное количество байт памяти. Под Integer 4 байта, под Double 8 байт, под Char 1 байт и так далее.

Но команды, которые манипулируют данными, хранят адрес только первого байта переменной. Информация о том, сколько надо прочитать байт и как эту цепочку байт интерпретировать, также хранится в команде.

Совокупность длины переменной и способа интерпретации последовательности байт можно назвать типом данных.

Указанные типы называются простыми типами данных.

По мере развития вычислительной техники и возрастания её возможностей стали вводиться более сложные, структурированные типы данных.

Чтобы работать с типом данных «массив» надо хранить информацию о том, что мы имеем дело с последовательностью байт, где начинается эта

последовательность, указать общее количество байт и на какие «порции» надо делить эту последовательность (указать тип данных).

Обычный массив характерен тем, что длина всех элементов массива одинакова.

В отличие от него, динамический массив может иметь разную мощность по разным измерениям. Например, двумерный динамический массив может содержать по первому измерению 5 элементов, а по второму — 10.

Но тип всех элементов всё равно остаётся одинаковым. Например, Integer.

Тип данных «запись».

Ещё более сложный тип данных delphi record — «запись». Внутри записи могут содержаться поля разного типа. Поэтому описание типа «запись» должно содержать информацию об адресе начала записи; о длине записи; список адресов начала полей, составляющих запись, и тип этих полей.

Объявляется запись следующим образом:

type tRec=record J:integer, sh:string[20]; ss:string; d:double; ar:array[1..3] of char; ex1,ex2:extended; end;

Нотация обращения к полям записи следующая:

var vRec:tRec;

vRec.J:=6;

vRec.sh:=’слово’; //не более 20 символов для короткой строки.

vRec.ss:=’предложение любой длины’; //длинная строка

vRec.d:=10.255; vRec.ex1:=456.89; vRec.ex2:=789.023;

vRec.ar[1]:=’A’; vRec.ar[2]:=’B’; vRec.ar[3]:=’C’;

Заметим, что полем может служить другая запись!

Например:

type tRec1=record JJ:integer, end;

type tRec=record J:integer, sh:string[20]; ss:string; d:double; ar:array[1..3] of char; ex1,ex2:extended; r1:tRec1 end;

Тогда для формирования значения JJ надо записать:

vRec.r1.JJ:=20;

Не прадо ли, очень похоже:

Form1.Memo1.Text ?

Теперь сделаем «петлю» и ещё раз вернёмся к типу «string».

Ещё раз о типе «string».

В типе «string» первые 12 байт служебные. В них указывается длина строки.

Номер кодовой таблицы символов (в какой язык интерпретировать числа, записанные в байтах, составляющих строку). Счётчик ссылок (он увеличивается на 1, когда выполняется s2:=s1, где s1 и s2 — строковые переменные).

Конец строки обозначается «терминальным нулём» — символом #0.

Символы пронумерованы по порядку, начиная с 1. К символу номер N можно обратиться, записав s1[5]. Если, например, в s1 хранится слово «строка», то s1[4] вернёт символ «к».

На примере строки мы посмотрели, как усложняется описание типа. Непосредственно данным в памяти предшествует несколько байт, описывающих структуру этих данных.

Само обращение к данным происходит по ссылке (по адресу, который записан в переменной, объявленной как тип String).

Но и само описание структуры данных переменной сложного типа можно разместить отдельно от самих данных, оставив пере данными только ссылку на область памяти, где хранится описание (тип) структуры данных.

Записи являются как бы предшественниками такого типа данных, как объект.

Понятие «объект» как особый тип данных.

К полям записи обращаются по нотации «переменная_запись»«.»«имя_поля».

Такая же нотация характерна и для объекта. Вспомним, что компоненты Delphi — это объекты, встроенные в IDE (в среду разработки).

Но объекты принципиально отличаются от записей. Настолько же, насколько обычная переменная отличается от динамической.

Объекты содержат не только данные (которые в объекте называются полями), но и процедуры (и функции).

К этим процедурам можно обращаться с помощью всё той же нотации с «точкой», как и к полям с данными.

Например, вспомним, как мы очищали содержимое компонента Memo (удаляли из него весь текст).

Для этого мы использовали процедуру (в объектах встроенные процедуры называются методами!) Clear. Так как ей не нужны параметры, её можно писать без скобок, то есть вместо Clear() записать просто Clear.

Поэтому мы использовали следующее предложение:

Form1.Memo1.Clear;

Сам объект Memo1 создаётся по шаблону (типу) Tmemo.

Более того. Сами типы являются объектами, поставляемыми со средой IDE. В них содержится метод (процедура) Create, называемый конструктором.

Собственно, он и создаёт экземпляр объекта в программе по собственному образу и подобию. Объект — тип может быть только один в пределах видимости IDE. Но своих копий (экземпляров) он может создать сколько угодно (конечно, каждому экземпляру должно быть дано уникальное имя).

В программе экземпляр объекта оформляется как переменная объектного типа.

Например:

Здесь объявлены переменная Form1 три переменных типа Tmemo.

var Form1: Tform1; Memo1:TMemo; Memo2:TMemo; Memo3:TMemo; и так далее.

Tform1, Tmemo и другие встроенные в IDE объекты-типы называются Delphi компонентами. При размещении компонента на форму IDE вызывает конструктор объекта-типа автоматически при размещении компонента на форму.

При создании собственных объектов программист сначала конструирует типобъект, а потом вызывает метод Create этого типа для создания экземпляра объекта.

Замечание. На будущее — типы, по которым создаются объекты, в объектном программировании называются «классами (Class)».

***

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

О записи данных в нетипизированный файл в следующем посте.

Обновлено: 07.01.2021 — 13:24

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *