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

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

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

7.2.8 Функция filesize

Одной из проблем при копировании данных из типизированного файла в массив является невозможность корректного выделения памяти под массив. При выделении памяти заранее неизвестно, сколько элементов находится в файле. Для решения этой задачи существует функция filesize(f) (f — файловая переменная), которая возвращает значение типа longint — число реальных компонентов в открытом файле, связанном с файловой переменной f. Для пустого файла функция возвращает число 0.

Рассмотрим использование функции filesize при переписывании чисел из файла вещественных чисел в массив.

ЗАДАЧА 7.3. Переписать содержимое файла вещественных чисел в массив.
program Project1;
{$mode objfpc}{$H+}
uses Classes, SysUtils
{ you can add units after this };
//Massiw - тип данных - массив из 1000 элементов.
type
	massiw=array [ 1.. 1000 ] of real;
var
f : file of real;
//a - указатель на массив;
a :^ massiw;
n, i : word;
begin
//Связываем файловую переменную с реальным файлом на диске.
assign file ( f, ’ /home/ evgeniy/pascal /6/ pr1 / abc. dat ’ );
//Открываем файл для чтения.
reset ( f );
//Записываем в переменную n количество элементов в файле f.
n:= file size ( f );
writeln ( ’в файле  ’, n, ’  чисел ’ );
//Выделяем память для динамического массива a
//из n вещественных чисел.
getmem( a, n * sizeof ( real ) );
for i :=1 to n do
begin
//Считываем очередной элемент из файла в массив.
read ( f, a ^[ i ] );
//Вывод элемента на экран.
write ( a ^[ i ] : 1 : 3, ’   ’ )
end;
//Освобождаем память, выделенную для динамического массива.
freemem ( a, n * sizeof ( real ) );
//Закрываем файл.
close file ( f );
readln;
end.

7.2.9 Функция filepos

Функция filepos(f) возвращает значение типа longint — текущую позицию в открытом файле, связанном с файловой переменной f. Сразу после открытия файла значение filepos(f) равно 0. После прочтения последнего компонента из файла значение filepos(f) совпадает со значением filesize(f). Достижение конца файла можно проверить с помощью условия:

if filepos ( f )= file size ( f ) then
writeln ( ’достигнут конца файла ’ );

7.2.10 Процедура seek

Процедура seek(f,n) устанавливает указатель в открытом файле, связанном с файловой переменной f, на компонент с номером n (нумерация компонентов идет от 0). Затем значение компонента может быть считано.

7.2.11 Процедура truncate

Процедура truncate(f), где f — имя файловой переменной, отсекает часть открытого файла, начиная с текущего компонента, и подтягивает на его место конец файла.

Использование процедур seek и truncate рассмотрим на примере решения следующих двух несложных задач по обработке файлов.

ЗАДАЧА 7.4. В файле /home/evgeniy/pascal/6/pr1/abc.dat вещественных чисел поменять максимальный и минимальный элементы.

Рассмотрим два варианта решения этой задачи.

В первом, консольном варианте программы после считывания компонентов файла в массив происходит поиск минимального и максимального элементов массива и их индексов. Затем максимальное и минимальное значения перезаписываются в файл.

program Project1;
{$mode objfpc}{$H+}
uses Classes, SysUtils
{ you can add units after this };
var f : file of real;
i, nmax, nmin : integer;
a : array [ 0.. 200 ] of real;
max, min : real;
begin
assignfile ( f, ’ /home/ evgeniy/pascal /6/ pr1 / abc. dat ’ );
reset ( f );
//Cчитываем компоненты файла в массив а.
for i :=0 to file size ( f ) -1 do
begin
read ( f, a [ i ] );
write ( a [ i ] : 1 : 2, ’   ’ );
end;
//Начальное присваивание максимального и
//минимального элементов массива и их индексов.
max:=a [ 0 ]; nmax : = 0;
min:=a [ 0 ]; nmin : = 0;
//Основной цикл для поиска максимального b
//минимального элементов массива и их индексов.
for i :=1 to file size ( f ) -1 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;
//Перезапись максимального и минимального значений в файл.
//Передвигаем указатель файла к максимальному элементу.
seek ( f, nmax );
//Записываем на место максимального элемента минимальный.
write ( f, min );
//Передвигаем указатель файла к минимального элементу.
seek ( f, nmin );
//Записываем на место максимального элемента минимальный.
write ( f, max );
//Обязательно закрываем файл.
closefile ( f ); readln;
end.

Вторую версию программы напишем как полноценное приложение. Использовать массив в программе не будем. Будет организован единственный цикл, в котором очередное значение считывается в переменную a и осуществляется поиск минимального и максимального элементов среди компонентов файла и их индексов. Затем происходит перезапись в файл максимального и минимального значений.

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

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

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

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

Расположим компоненты на форме примерно так, показано на рис. 7.7.

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

procedure TForm1. FormCreate ( Sender : TObject );
begin
	Form1. Caption :=
’Обмен максимального и минимального элемента в файле ’;
	label1.Caption := ’Исходный файл ’;
	label1.Visible := False;
	label2.Caption := ’Файл после преоброзования ’;
	label2.Visible := False;
	Edit1.Text := ’ ’;
	Edit1.Visible := false;
	Edit2.Text := ’ ’;
	Edit2.Visible := false;
	OpenDialog1. Filter :=
’Файлы вещественных_чисел | *. datВсе |  файлы | *. * ’;
OpenDialog1. InitialDir := ’ /home/ evgeniy/pascal /6/ pr1 ’;
	Button1. Caption := ’Преобразовать файл ’;
	Button2. Caption := ’Выход ’;
	Button2. Visible := False;
end;
Окно программы решения задачи 7.4 при запуске

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

Авторы надеются, что читателям, дочитавшим книгу до этого момента, текст процедуры TForm1.FormCreate понятен без пояснений.

При запуске программы окно формы будет иметь вид, представленный на рис. 7.8.

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

procedure TForm1. Button1Click ( Sender : TObject );
var
f : file of real;
i, nmax, nmin : integer;
a, max, min : real;
s1, s : string;
begin
//Открываем диалоговое окно для выбора файла.
if OpenDialog1. Execute then
begin
//В переменную s записываем полное имя файла.
	s := OpenDialog1. FileName;
//Связываем файловую переменную с файлом на диске.
	assignfile ( f, s );
//Открываем файл в режиме чтения.
	reset ( f );
//Делаем видимыми первую метку и поле ввода.
	label1 Visible := true;
	Edit1.Visible := true;
//В строке s1 будем формировать содержимое файла.
	S1:= ’ ’;
//Цикл для последовательного чтения всех элементов из файла
//вещественных чисел.
	for i :=0 to file size ( f ) -1 do
	begin
//Считывание очередного элемента массива в переменную a.
		read ( f, a );
		if i =0 then
//Начальное присваивание максимального и минимального значений
//и их индексов.
		begin
			max:=a; nmax:= i;
			min:=a; nmin:= i;
		end
		else
		begin
//Сравнение текущего значения с максимальным (минимальным).
			if max<a then
			begin
				max:=a;
				nmax:= i
			end;
			if min>a then
			begin
				min:=a;
				nmin:= i
			end
		end;
//Добавление очередного значения к выходной строке s1.
		s1 := s1+FloatToStr ( a)+ ’   ’;
	end;
//Вывод содержимого файла в первое текстовое поле
//редактирования.
	Edit1. Text := s1;
//Запрет изменения текстового поля.
	Edit1. ReadOnly:= true;
//Перезапись максимального и минимального значений в файл.
//Передвигаем указатель файла к максимальному элементу.
	seek ( f, nmax );
//Записываем на место максимального элемента минимальный.
	write ( f, min );
//Передвигаем указатель файла к максимальному элементу.
	seek ( f, nmin );
//Записываем на место минимального элемента максимальный.
	write ( f, max );
//Обязательно закрываем файл.
	closefile ( f );
	reset ( f );
//Делаем видимыми вторую метку и поле ввода.
	label2.Visible := true;
	Edit2.Visible := true;
//Считываем данные из преобразованного файла
	s1 := ’ ’;
	for i :=0 to file size ( f ) -1 do
	begin
		read ( f, a );
//Добавление очередного значения из преобразованного файла
//к выходной строке s1.
	s1 := s1+FloatToStr ( a)+ ’   ’;
end;
//Вывод содержимого преобразованного файла во второе текстовое
//поле редактирования.
	Edit2. Text := s1;
//Запрет изменения текстового поля.
	Edit2. ReadOnly:= true;
//Делаем видимой вторую кнопку.
	Button2. Visible :=True;
	CloseFile ( f );
	end;
end;

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

procedure TForm_File. Button2Click ( Sender : TObject );
begin
	Close;
end;

При щелчке по кнопке Преобразовать файл появляется окно выбора файла, подобное представленному на рис. 7.5. После выбора файла в нём происходит обмен максимального и минимального элементов и вывод содержимого файла до и после преобразования (см. рис. 7.9). При щелчке по кнопке Выход работа программы завершается.

Окно программы решения задачи 7.4 после преобразования файла

увеличить изображение
Рис. 7.9. Окно программы решения задачи 7.4 после преобразования файла

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

ЗАДАЧА 7.5. Задан файл вещественных чисел abc.dat. Удалить из него максимальный и минимальный элементы.

Рассмотрим две программы, решающие эту задачу. Программы будем создавать как консольные приложения в Lazarus. Алгоритм первой состоит в следующем: считываем компоненты файла в массив, в котором находим максимальный и минимальный элементы и их номера. Открываем файл для записи и вносим в него все элементы, за исключением максимального и минимального.

program Project1;
{$mode objfpc}{$H+}
uses Classes, SysUtils
{ you can add units after this };
var
f : file of real;
max, min : real;
j, i, nmax, nmin : integer;
a : array [ 1.. 300 ] of real;
begin
assignfile ( f, ’ /home/ evgeniy/pascal /6/ pr1 / abc. dat ’ );
reset ( f );
//Запоминаем в переменной j количество компонентов в файле.
j := filesize ( f );
//Считываем компоненты файла в массив а.
for i :=1 to j do read ( f, a [ i ] );
for i :=1 to j do write ( a [ i ] : 1 : 2, ’   ’ );
writeln;
closefile ( f );
//Открываем файл для записи.
rewrite ( f );
//Начальное присваивание максимального и
//минимального элементов массива и их индексов.
max:=a [ 1 ]; min:=a [ 1 ];
nmax : = 1; nmin : = 1;
//Основной цикл для поиска максимального и
//минимального элементов массива и их индексов.
for i :=2 to j 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;
//Перезапись элементов массива в файл, за исключением
//элементов с номерами nmax и nmin.
writeln ( ’Преобразованный_файл ’ );
for i :=1 to j do
	if ( i <>nmax) and ( i <>nmin ) then
	begin
		write ( f, a [ i ] );
//Вывод записанного в файл элемента на экран.
		write ( a [ i ] : 1 : 2, ’   ’ );
	end;
closefile ( f );
readln;
end.

Вторая программа работает следующим образом. Находим максимальный и минимальный элементы и их номера среди компонентов файла. Если nmin > nmax, то меняем содержимое переменных nmin и nmax. Далее элементы, лежащие между минимальным и максимальным (формально между элементами с номерами nmin и nmax), сдвигаем на один порядок влево. Тем самым мы убираем элемент с номером nmin. После этого все компоненты, лежащие после элемента с номером nmax, сдвинем на два порядка влево. Этим мы сотрём максимальный элемент. Затем два последних компонента в файле необходимо удалить.

program Project1;
{$mode objfpc}{$H+}
uses Classes, SysUtils
{ you can add units after this };
var
f : file of real;
a : real;
max, min : real;
i, nmax, nmin : integer;
begin
assignfile ( f, ’ /home/ evgeniy/pascal /6/ pr1 / abc. dat ’ );
reset ( f );
//Поиск максимального и минимального элементов в файле и их
//индексов.
writeln ( ’Исходный файл ’ );
for i :=0 to filesize ( f ) -1 do
begin
	read ( f, a );
	write ( a : 1 : 2, ’   ’ );
	if i =0 then
	begin
		max:=a;
		nmax:= i;
		min:=a;
		nmin:= i
	end
	else
	begin
		if a>max then
		begin
			max:=a;
			nmax:= i;
		end;
		if a<min then
		begin
			min:=a;
			nmin:= i;
		end
	end
end;
writeln;
//Сравниваем nmin и nmax.
if nmax<nmin then
begin
	i :=nmax;
	nmax:=nmin;
	nmin:= i
end;
//Сдвигаем элементы, лежащие между компонентами
//с номерами nmin и nmax, на один влево.
for i :=nmin to nmax-2 do
begin
	seek ( f, i +1);
	read ( f, a );
	seek ( f, i );
	write ( f, a );
end;
//Сдвигаем элементы, лежащие после компонента
//с номером nmax, на два влево.
for i :=nmax to filesize ( f ) -3 do
begin
	seek ( f, i +1);
	read ( f, a );
	write ( a : 1 : 2 );
	seek ( f, i - 1);
	write ( f, a );
	write ( a : 1 : 2 );
end;
//Отрезаем последние два компонента.
truncate ( f );
closefile ( f );
reset ( f );
//Вывод преобразованного файла.
writeln ( ’Преобразованный_файл ’ );
for i :=1 to file s i z e ( f ) do
begin
	read ( f, a );
//Вывод записанного в файл элемента на экран.
	write ( a : 1 : 2, ’ _ ’ );
	end;
closefile ( f );
readln;
end.

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

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

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

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

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

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