Компания ALT Linux
Опубликован: 10.04.2015 | Доступ: свободный | Студентов: 762 / 0 | Длительность: 14:03:00
Специальности: Программист, Преподаватель
Лекция 7:

Обработка файлов средствами Free Pascal

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >

7.2.7 Чтение и запись данных в файл

Для записи данных в файл можно использовать процедуру write:

write ( f, x1, x2,..., xn );

write ( f, x );

здесь

  • f — имя файловой переменной,
  • x, x1, x2,..., xn — имена переменных, значения из которых записываются в файл.

Тип компонентов файла обязательно должен совпадать с типом переменных. При выполнении процедуры write значения x1, x2,..., xn последовательно записываются в файл (начиная с текущей позиции), связанный с файловой переменной f.

Для чтения информации из файла, связанного с файловой переменной f, можно воспользоваться процедурой read:

read ( f, x1, x2, x3,..., xn );

read ( f, x );

здесь

  • f — имя файловой переменной,
  • x, x1, x2,..., xn — имена переменных, в которые считываются значения из файла.

Процедура read последовательно считывает компоненты из файла, связанного с файловой переменной f, в переменные x1, x2,..., xn. При считывании очередного значения доступным становится следующее. Следует помнить, что процедура read не проверяет, достигнут ли конец файла. За этим нужно следить с помощью функции eof.

Для того чтобы записать данные в файл, необходимо выполнить следующее:

  1. Описать файловую переменную.
  2. Связать её с физическим файлом (процедура AssignFile).
  3. Открыть файл для записи (процедура rewrite).
  4. Записать данные в файл (процедура write).
  5. Обязательно закрыть файл (процедура CloseFile).

Рассмотрим создание компонентного файла на примере решения следующей несложной задачи.

ЗАДАЧА 7.1. Создать типизированный файл и записать туда n вещественных чисел.

Алгоритм решения задачи состоит из следующих этапов:

  1. Открыть файл для записи с помощью оператора rewrite.
  2. Ввести значение n.
  3. В цикле (при i, меняющемся от 1 до n) ввести очередное вещественное число a, которое сразу же записать в файл с помощью процедуры write.
  4. Закрыть файл с помощью процедуры closefile.

Текст консольного приложения Lazarus, предназначенного для решения данной задачи, приведён ниже.

program pr1;
{$mode objfpc}{$H+}
uses
	Classes, SysUtils
	{you can add units after this};
	var f : file of real;
		i, n : integer;
		a : real;
begin
//Связываем файловую переменную с файлом на диске.
			AssignFile ( f, ’ /home/ evgeniy/pascal /6/ pr1 / abc. dat ’ );
//Открываем пустой файл для записи.
			rewrite ( f );
//Определяем количество элементов в файле.
			write ( ’ n= ’ ); readln ( n );
//В цикле вводим очередной элемент и записываем его в файл.
			for i :=1 to n do
	begin
		write ( ’ a= ’ ); readln ( a );
		write ( f, a );
	end;
//Закрываем файл.
//При записи данных в файл это делать обязательно!!!
	CloseFile ( f )
end.
ЗАДАЧА 7.2. В папке /home/evgeniy/pascal/6/pr2/ находятся файлы вещественных чисел с расширением dat. В выбранном пользователем файле удалить все числа, меньшие среднего арифметического, расположенные между максимальным и минимальным элементами.

В задаче предполагается выбор пользователем файла для обработки. Для этого понадобится специальный компонент для выбора файла. Решение задачи 7.2 начнём со знакомства с компонентом OpenDialog. Этот компонент предназначен для создания стандартного диалогового окна выбора файла и расположен первым на странице Dialogs (см. рис. 7.1).

Компоненты страницы Dialogs

Рис. 7.1. Компоненты страницы Dialogs

Среди основных свойств этого компонента можно выделить:

  • FileName: String — полное имя выбранного пользователем файла;
  • Filter: String — строка, которая возвращает фильтры отбираемых файлов; это свойство можно задать с помощью редактора фильтров или с помощью специальной строки.

Для вызова редактора необходимо щёлкнуть по кнопке (свойства Filter), после чего появится окно редактора фильтров (см. рис. 7.2).

Окно редактора фильтров состоит из двух столбцов: Filter name — имя фильтра (например, все файлы — программы Паскале); Filter — соответствующая имени фильтра маска (фильтру "все файлы" соответствует маска "*.*", фильтру "программы на Паскале" — маска "*.pas".

Специальная строка состоит из последовательных имен фильтров и соответствующих им масок, разделённых символом "|". Специальная строка, соответствующая фильтру, представленному на рис. 7.2, имеет вид:

OpenDialog1. Filter :=
’Программы_на_C|*.c|Программы_на_Паскале|*.pas|Все_файлы|*.*’;
Редактор фильтров

Рис. 7.2. Редактор фильтров

Первый фильтр в списке является фильтром по умолчанию, в примере на рис. 7.2 фильтр по умолчанию — "Программы на C". InitialDialog — имя каталога по умолчанию для выбора файлов. DefaultExt — расширение, добавляемое к имени файла по умолчанию, если пользователь при ручном вводе имени файла не указал расширение.

Основным методом для компонента OpenDialog является логическая функция Execute, которая приводит к открытию диалогового окна в соответствии со свойствами компонента. Функция Execute возвращает true, если пользователь выбрал файл какимлибо методом. Если пользователь нажал в диалоговом окне Отмена (Cancel), то метод Execute возвращает false. Имя выбранного файла возвращается в свойстве FileName.

Таким образом, вызов диалогового окна можно записать так:

var
s : String;
begin
	if OpenDialog1. Execute then
	s := OPenDialog1. FileName;
{Имя файла, выбранного пользователем, хранится в переменной s}
end;

Разобравшись с компонентом для выбора файла, вернемся к задаче 7.2. Можно выделить следующие этапы решения задачи.

  1. Выбор файла.
  2. Чтение данных из файла в массив вещественных чисел.
  3. Удаление в массиве вещественных чисел всех чисел, меньших среднего арифметического, расположенных между максимальным и минимальным элементами.
  4. Запись преобразованного массива в файл.

Разработку программы начнём с создания графического приложения (Проект — Создать Проект — Приложение).

На форме расположим следующие компоненты:

  1. Две метки Label1 и Label2 для подписи.
  2. Memo1 — компонент, в котором будем хранить содержимое исходного файла.
  3. Memo2 — компонент, в котором будет храниться преобразованный файл.
  4. OpenDialog1 — компонент для выбора имени обрабатываемого файла.
  5. Button1 — кнопка для запуска программы.
  6. Button2 — кнопка для завершения программы.

Установим следующие свойства формы и компонентов (см. табл. 7.1, см. табл. 7.2, см. табл. 7.3, см. табл. 7.4, см. табл. 7.5, см. табл. 7.6, см. табл. 7.7, см. табл. 7.8).

Таблица 7.1. Свойства формы
Свойство Caption Name
Значение Преобразование файла Form_File
Таблица 7.2. Свойства метки label1
Свойство Caption Visible
Значение Файл до преобразования False
Таблица 7.3. Свойства метки label2
Свойство Caption Visible
Значение Файл до преобразования False
Таблица 7.4. Свойства компонента Memo1
Свойство Lines Visible
Значение '' False
Таблица 7.5. Свойства компонента Memo2
Свойство Lines Visible
Значение '' False
Таблица 7.6. Свойства компонента OpenDialog1
Свойство InitDialog DefaultExt
Значение /home/evgeniy/pascal/6/pr2/ dat
Таблица 7.7. Свойства кнопки Button1
Свойство Caption Name Visible
Значение Преобразовать файл Button_File True
Таблица 7.8. Свойства кнопки Button2
Свойство Caption Name Visible
Значение Закрыть Button_Close False
Форма с расположенными на ней компонентами

увеличить изображение
Рис. 7.3. Форма с расположенными на ней компонентами
Приложение при запуске

увеличить изображение
Рис. 7.4. Приложение при запуске

Расположим компоненты на форме подобно тому, как показано на рис. 7.3.

При запуске программы на выполнение все компоненты, кроме кнопки "Преобразовать файл", будут невидимыми, свойство Visible установлено в False. Окно приложения при запуске показано на рис. 7.4.

Проектирование интерфейса приложения завершено. Осталось написать тексты обработчиков событий.

При создании формы установим свойство Filter компонента OpenDialog1. Поэтому подпрограмма FormCreate будет такой.

procedure TForm_File. FormCreate ( Sender : TObject );
begin
OpenDialog1. Filter :=
’Файлы_вещественных_чисел|*.dat|Все_файлы|*.*’;
end;

При щелчке по кнопке "Преобразовать файл" должно происходить следующее:

  • Выбор файла из диалогового окна.
  • Считывание данных из файла в массив вещественных чисел.
  • Установка свойства Visible в true у компонентов label1 и Memo1.
  • Вывод содержимого массива в Memo1.
  • Преобразование массива.
  • Запись преобразованного массива в файл.
  • Установка свойства Visible в true у компонентов label2 и Memo2.
  • Вывод преобразованного массива в Memo2.
  • Установка свойства Visible в True у компонента Button_Close.

Ниже приведён текст обработки события Button_FileClick с подробными комментариями.

procedure TForm_File. Button_FileClick ( Sender : TObject );
var
f : file of real;
s : string;
a : array [ 1.. 100 ] of real;
nmax, nmin, i, j, n : integer;
sum, max, min : real;
begin
//Открываем диалоговое окно для выбора файла.
	if opendialog1.execute then
	begin
//Имя выбранного файла считываем в переменную s.
	s := OpenDialog1. FileName;
//Связываем файловую переменную с файлом на диске.
	AssignFile ( f, s );
//Открываем файл для чтения.
	Reset ( f );
//Обнуляем счетчик элементов массива.
	n : = 0;
//Делаем видимыми первую метку и компонент Memo1.
	label1. Visible := true;
	Memo1. Visible := true;
//Переменная sum служит для нахождения суммы компонентов
//файла.
	Sum: = 0;
//Пока не встретится конец файла, будем считывать очередной
//компонент.
	while not eof ( f ) do
	begin
//Индекс массива увеличиваем на 1.
		n:=n+1;
//Считываем очередной элемент из файла в массив.
		read ( f, a [ n ] );
//Накапливаем сумму элементов массива.
		sum:=sum +a [ n ];
//Выводим очередной элемент в Memo1.
		Memo1. Lines. Add( FloatToStr ( a [ n ] ) );
	end;
//Закрываем файл.
	CloseFile ( f );
//Находим среднее арифметическое элементов массива.
	sum:=sum/n;
//Выполняем поиск максимального, минимального элементов
//в массиве и их индексов.
	max:=a [ 1 ]; min:=max; nmin : = 1; nmax : = 1;
	for i :=2 to n do
	begin
		if a [ i ]>max then
		begin
			max:=a [ i ];
			nmax:= i;
		end;
		if a [ i ]<min then
		begin
			min:=a [ i ];
			nmin:= i;
		end;
	end;
//Если максимальный элемент расположен раньше минимального,
//то меняем местами nmin и nmax.
	if nmax<nmin then
	begin
		i :=nmax;
		nmax:=nmin;
		nmin:= i;
	end;
	i :=nmin+1;
//Цикл для удаления элементов, расположенных между
//максимальным и минимальным.
	while ( i <nmax) do
	begin
//Если очередной элемент массива меньше среднего
//арифметического, то
		if a [ i ]<sum then
		begin
//удаляем его.
			for j := i to n-1 do
			a [ j ] : = a [ j + 1 ];
//После удаления уменьшаем количество элементов и номер
//максимального на 1.
			n:=n _1;
			nmax:=nmax-1;
		end
//Если очередной элемент массива больше среднего
//арифметического, то
	else
//переходим к следующему.
		i := i +1;
	end;
//Делаем видимыми вторую метку и компонент Memo2.
	label2. Visible := true;
	Memo2. Visible := true;
//Открываем файл для записи.
	rewrite ( f );
//Преобразованный массив записываем в файл и выводим
//в компонент Memo2.
	for i :=1 to n do
	begin
		write ( f, a [ i ] );
		Memo2. Lines. Add( FloatToStr ( a [ i ] ) );
	end;
//Закрываем файл, делаем видимой вторую кнопку.
	CloseFile ( f );
	Button_Close. Visible :=True;
end;
end;

При щелчке по кнопке "Закрыть" программа должна завершать свою работу. Поэтому текст обработчика щелчка по кнопке будет очень простым.

Диалоговое окно выбора файла

Рис. 7.5. Диалоговое окно выбора файла
procedure TForm_File. Button_CloseClick ( Sender : TObject );
begin
	Close;
end;

Проверим функционирование созданного приложения. После запуска программы появляется окно, подобное представленному на рисунке 7.4. Щелчком по кнопке Преобразовать файл открывается диалоговое окно выбора файла (рисунок 7.5).

После щелчка по кнопке OK, окно программы становится похожим на представленное на рис. 7.6. Щелчок по кнопке Закрыть завершает работу приложения. Задача 7.2 решена, разработано функционирующее приложение.

В связи с тем, что файл — последовательная структура данных, при решении задачи пришлось целиком считывать содержимое файла в массив, проводить обработку данных в массиве и только затем записывать в файл. Такой метод не всегда удобен. Кроме того, при считывании данных из файла в массив мы ограничены описанием статического массива. Если в файле окажется больше элементов, чем при описании статического массива (в нашем случае > 100), то программа не будет правильно работать. Использование динамического массива не решит эту проблему, потому что неизвестно количество элементов в массиве.

Окно с результатами работы программы

увеличить изображение
Рис. 7.6. Окно с результатами работы программы

Для решения этой проблемы в языке Free Pascal реализован прямой доступ к файлу с помощью рассмотренных далее подпрограмм работы с файлами.

< Лекция 6 || Лекция 7: 12345 || Лекция 8 >
Юрий Шутиков
Юрий Шутиков

По первому тесту выполнил дважды задания. Результат получается правильный (проверял калькулятором). Пишет, что "Задание не проверено" и предлагает повторить. 
 

Евгений Силуков
Евгений Силуков

Еще в декабре выполнил тест №1, а его все так и не проверили.