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

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

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

7.3 Бестиповые файлы в языке Free Pascal

Для хранения данных различного типа удобно использовать бестиповые файлы. При открытии бестиповых файлов следует использовать расширенный синтаксис процедур reset и rewrite.

Reset ( var f : File; BuferSize : word );

Rewrite ( var f : File; BuferSize : word );

Необязательный параметр BufSize определяет размер блока передачи данных — количество байт, считываемых или записываемых в файл данных за одно обращение к нему. Если этот параметр отсутствует, то используется значение, устанавливаемое по умолчанию при открытии файла (128). Наибольшей гибкости можно достичь при размере блока 1 байт.

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

BlockWrite ( var f : file; var X; Count : word; var WriteCount : word );

здесь f — имя файловой переменной, Xимя переменной, из которой данные записываются в файл, Count — количество блоков размером BufSize, записываемых в файл; необязательный параметр WriteCount определяет реальное количество записанных в файл блоков.

Процедура BlockWrite записывает Count блоков в файл, связанный с файловой переменной f2Размер блока определяется при выполнении процедур Reset, Rewrite., из переменной X. При корректной записи в файл возвращаемое процедурой BlockWrite значение WriteCount совпадает c Count.

При чтении данных из бестипового файла используется процедура BlockRead:

BlockRead ( var f : file; var Y; Count : word; var ReadCount : word );

где f — имя файловой переменной, Yимя переменной, в которую считываются данные из файла, Count — количество блоков размером BufSize, считываемых из файла, необязательный параметр ReadCount определяет количество блоков размером BufSize, реально считанных из файла.

BlockRead считывает из файла, связанного с файловой переменной f, Count блоков в переменную Y. При корректном чтении из файла возвращаемое процедурой BlockRead значение ReadCount должно совпадать c Count.

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

ЗАДАЧА 7.6. В бестиповом файле хранится массив вещественных чисел и количество элементов в нём. Удалить из файла максимальное вещественное число.

Напишем консольное приложение для создания файла.

program Project1;
{$mode objfpc}{$H+}
uses
	Classes, SysUtils
	{ you can add units after this };
type
massiv=array [ 1.. 100000 ] of real;
var i,N: word;
	f : file;
	x :^ massiv;
begin
Assignfile ( f, ’ /home/ evgeniy/pascal /6/pr_6/ new_file. dat ’ );
//Открываем файл для записи, размер блока передачи данных - 1
//байт.
rewrite ( f, 1 );
//Ввод числа N - количества целых положительных чисел в
//файле
write ( ’N= ’ ); readln (N);
//Записываем в файл f целое число N, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной N.
BlockWrite ( f,N, sizeof ( word ) );
//Выделяем память для N элементов массива x вещественных
//чисел.
getmem( x,N*sizeof ( real ) );
//Ввод массива.
writeln ( ’Введите массив ’ );
for i :=1 to N do
begin
	write ( ’ x ( ’, i, ’ )= ’ );
	readln ( x ^[ i ] );
end;
for i :=1 to N do
//Записываем в файл f вещественное число x^[i], а точнее 8
//блоков (sizeof(real)=8) по одному байту из переменной x^[i].
BlockWrite ( f, x ^[ i ], sizeof ( real ) );
//Запись массива в файл можно осуществить и без цикла с
//помощью следующего обращения к функции BlockRead
//BlockWrite(f,x^,N*sizeof(real));
//Запись массива в бестиповый файл без цикла с помощью одного
//оператора BlockWrite(f,x^,N*sizeof(тип)) кажется авторам
//предпочтительнее.
//Закрываем файл.
CloseFile ( f );
//Освобождаем память.
freemem ( x,N*sizeof ( real ) );
readln;
end.

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

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

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

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

Основные свойства компонентов будем устанавливать программно при создании формы. Программа решения задачи 7.6 будет выполняться при щелчке по кнопке. Полный текст модуля с необходимыми комментариями:

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LResources, Forms, Controls, Graphics,
Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class (TForm)
//На форме находятся:
//Кнопка.
	Button1 : Tbutton;
//Поле редактирования - для вывода содержимого исходного
//файла.
	Edit1 : Tedit;
//Поле редактирования - для вывода содержимого файла после
//преобразования.
	Edit2 : Tedit;
//Метки для подписи полей редактирования.
	Label1 : TLabel;
	Label2 : Tlabel;
//Компонент для выбора файла.
	OpenDialog1 : TOpenDialog;
	procedure Button1Click ( Sender : TObject );
	procedure FormCreate ( Sender : TObject );
private
	{ private declarations }
public
	{ public declarations }
end;
	massiv=array [ 1.. 50000 ] of real;
var
	Form1 : TForm1;
	f : file;
implementation
{ TForm1 }
//Текст процедуры обработчика события "Щелчок по кнопке".
procedure Tform1. Button1Click ( Sender : TObject );
	var x :^ massiv;
	y : array [ 1.. 3000 ] of real;
	i,N: word;
	max : real;
	nmax : word;
	s : string;
begin
//Выбираем файл, который будем обрабатывать.
if OpenDialog1. Execute then
begin
//Имя обрабатываемого файла записываем в переменную s.
	s := OpenDialog1. FileName;
//Связываем файловую переменную с именем файла, хранящимся в
//переменной s.
	AssignFile ( f, s );
//Открываем файл для чтения, размер блока передачи данных 1
//байт.
	Reset ( f, 1 );
//Считываем из файла f целое число (word) N, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной N.
	BlockRead ( f,N, sizeof ( word ) );
//Выделяем память для N элементов массива x вещественных
//чисел.
	getmem( x,N* sizeof ( real ) );
//Считываем из файла f N вещественных чисел в переменную x.
//Реально считываем N*sizeof(real) блоков по 1 байту.
//Заполняем массив X значениями, хранящимися в файле.
BlockRead ( f, x ^,N* sizeof ( real ) );
//Делаем видимыми первую метку и первый компонент Edit1.
	Label1. Visible := true;
	Edit1. Visible := true;
	for i :=1 to N do
//Добавление очередного значения из массива x к первому
//текстовому полю редактирования.
//В результате в первом текстом поле будет выведен исходный
//массив вещественных чисел.
	Edit1. Text := Edit1. Text+FloatToStrF ( x ^[ i ], ffFixed,5, 2)+ ’   ’;
//Поиск максимального элемента и его номера.
	max:=x ^ [ 1 ];
	nmax : = 1;
	for i :=2 to N do
	if x ^[ i ]>max then
	begin
		max:=x ^[ i ];
		nmax:= i;
	end;
//Удаление максимального элемента из массива.
	for i :=nmax to N -1 do
	x ^[ i ] : = x ^[ i + 1 ];
//Уменьшение количества элементов в массиве.
	N:=N-1;
//Закрываем файл.
	CloseFile ( f );
	AssignFile ( f, s );
//Открываем файл для записи.
	Rewrite ( f, 1 );
//Записываем в файл f целое число N, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной N.
	BlockWrite ( f,N, sizeof ( word ) );
	BlockWrite ( f,N, sizeof ( word ) );
//Запись массива в файл с помощью обращения к функции
//BlockRead.
	BlockWrite ( f, x ^,N* sizeof ( real ) );
//Закрываем файл.
	CloseFile ( f );
//Освобождаем память.
	freemem ( x,N* sizeof ( word ) );
//Чтение данных из преобразованного файла.
	AssignFile ( f, s );
	Reset ( f, 1 );
//Считываем из файла f целое число (word) N, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной N.
	BlockRead ( f,N, sizeof ( word ) );
//Выделяем память для N элементов массива x вещественных
//чисел.
	getmem( x,N* sizeof ( real ) );
//Считываем из файла f N вещественных чисел в переменную x.
//Реально считываем N*sizeof(real) блоков по 1 байту.
//Заполняем массив X значениями, хранящимися в файле.
	BlockRead ( f, x ^,N* sizeof ( real ) );
//Делаем видимыми вторую метку и второй компонент Edit2.
	Label2. Visible := true;
	Edit2. Visible := true;
//Содержимое массива x выводим в текстовое поле Edit2.
	for i :=1 to N do
	Edit2. Text := Edit2. Text+FloatToStrF ( x ^[ i ], ffFixed,5, 2)+ ’   ’;
//Закрываем файл и освобождаем память.
	CloseFile ( f );
	freemem ( x,N* sizeof ( real ) );
end;
end;
procedure TForm1. FormCreate ( Sender : TObject );
begin
//При создании формы устанавливаем свойства компонентов Edit1,
//Edit2, label1, label2 и кнопки Button1. Все компоненты,
//кроме кнопки, делаем невидимыми.
	Form1. Caption := ’Работа с бестиповыми файлами ’;
	Label1. Width := 80;
	Label1. Caption := ’Содержимое исходного файла ’;
	Edit1. Clear;
	Label2. Caption := ’Содержимое преобразованного файла ’;
	Label2. Width := 80;
	Edit2. Clear;
	Button1. Width :=150;
	Button1. Caption := ’Преобразование файла ’;
	Label1. Visible := false;
	Edit1. Visible := false;
	Label2. Visible := false;
	Edit2. Visible := false;
end;
initialization
	{$I unit1.lrs}
end.
Окно формы с компонентами

Рис. 7.10. Окно формы с компонентами

При запуске программы окно приложения будет таким, как на рис. 7.11.

После щелчка по кнопке Преобразовать файл появится окно выбора файла (см. рис. 7.12).

Окно программы после преобразования файла представлено на рис. 7.13.

Окно программы решения задачи 7.6 при запуске

Рис. 7.11. Окно программы решения задачи 7.6 при запуске
Окно выбора файла

Рис. 7.12. Окно выбора файла
Окно работающей программы

Рис. 7.13. Окно работающей программы
ЗАДАЧА 7.7. В бестиповом файле хранятся матрицы вещественных чисел A(N, M ), B(P, L) и их размеры. Умножить, если это возможно, A на B, результирующую матрицу C = A \cdot B дописать в файл.

Решение задачи начнём с написания консольной программы создания файла. Для этого определимся со структурой файла. Пусть в нём хранятся два значения типа word: N и M, затем матрица вещественных чисел A(N,M), затем значения P и L типа word и матрица B(P,L).

Ниже приведён листинг программы создания бестипового файла с комментариями.

program Project1;
{$mode objfpc}{$H+}
uses
Classes, SysUtils
{ you can add units after this };
var
	f : file;
	i, j, n,m, l, p : word;
	a, b : array [ 1.. 20, 1.. 20 ] of real;
begin
	AssignFile ( f, ’ Prim. dat ’ );
//Открываем файл для записи, размер блока передачи данных 1
//байт.
	rewrite ( f, 1 );
	write ( ’N= ’ ); readln (N);
	write ( ’M= ’ ); readln (M);
//Записываем в файл f целое число N, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной N.
	BlockWrite ( f,N, sizeof ( word ) );
//Записываем в файл f целое число M, а точнее 2 блока
//(sizeof(word)=2) по одному байту из переменной M.
	BlockWrite ( f,M, sizeof ( word ) );
writeln ( ’ Matrica  A ’ );
	for i :=1 to N do
	for j :=1 to M do
	begin
//Вводим очередной элемент матрицы.
		read (A[ i, j ] );
//Записываем в файл f вещественное число A[i,j], а точнее
//sizeof(real) блоков по одному байту из переменной A[i,j].
		BlockWrite ( f,A[ i, j ], sizeof ( real ) );
	end;
	write ( ’L= ’ ); readln (L );
	write ( ’P= ’ ); readln (P );
//Записываем в файл 2 блока по одному байту из переменной L.
	BlockWrite ( f, L, sizeof ( word ) );
//Записываем в файл 2 блока по одному байту из переменной P.
	BlockWrite ( f, P, sizeof ( word ) );
writeln ( ’ Matrica  B ’ );
	for i :=1 to L do
	for j :=1 to P do
	begin
		read (B[ i, j ] );
//Записываем в файл sizeof(real) блоков по одному байту из
//переменной B[i,j].
		BlockWrite ( f,B[ i, j ], sizeof ( real ) );
	end;
//Закрываем файл.
	CloseFile ( f );
end.

Теперь напишем консольное приложение Lazarus, с помощью которого из бестипового файла считаем матрицы A, B, их размеры, после чего вычислим матрицу С как произведение А и B.

program Project1;
{$mode objfpc}{$H+}
uses
Classes, SysUtils
{ you can add units after this };
var
	f : file;
	k, i, j, n,m, l, p : word;
	a, b, c : array [ 1.. 20, 1.. 20 ] of real;
begin
//Связываем файловую переменную с файлом на диске.
	AssignFile ( f, ’Pr_7_6. dat ’ );
//Открываем файл и устанавливаем размер блока в 1 байт.
	reset ( f, 1 );
//Считываем в переменную N из файла f 2 байта (sizeof(word)=2
//блоков по одному байту).
	BlockRead ( f,N, sizeof ( word ) );
//Считываем в переменную M из файла f 2 байта (sizeof(word)=2
//блоков по одному байту).
	BlockRead ( f,M, sizeof ( word ) );
	for i :=1 to N do
	for j :=1 to M do
//Считываем в переменную A[i,j] из файла f sizeof(real) байт
//(sizeof(real) блоков по одному байту).
	BlockRead ( f,A[ i, j ], sizeof ( real ) );
//Считываем в переменную L из файла f 2 байта.
	BlockRead ( f, L, sizeof ( word ) );
//Считываем в переменную P из файла f 2 байта.
	BlockRead ( f, P, sizeof ( word ) );
	for i :=1 to L do
	for j :=1 to P do
//Считываем в переменную B[i,j] из файла f sizeof(real) байт.
BlockRead ( f,B[ i, j ], sizeof ( real ) );
//Вывод матрицы A на экран.
writeln ( ’ Matrica  A ’ );
for i :=1 to N do
begin
	for j :=1 to M do
write (A[ i, j ] : 1 : 2, ’   ’ );
writeln; end;
//Вывод матрицы B на экран.
writeln ( ’ Matrica  B ’ );
for i :=1 to L do
begin
for j :=1 to P do
write (B[ i, j ] : 1 : 2, ’   ’ );
writeln
end;
//Проверяем, возможно ли умножение матриц, если да,
if m=l then
begin
//то умножаем матрицу А на B
for i :=1 to N do
for j :=1 to P do
begin
c [ i, j ] : = 0;
for k:=1 to M do
c [ i, j ] : = c [ i, j ]+a [ i, k ] * b [ k, j ]
end;
//Вывод матрицы C.
writeln ( ’ Matrica  C=A * B ’ );
for i :=1 to N do
begin
for j :=1 to P do
write (C[ i, j ] : 1 : 2, ’   ’ );
writeln
end;
//Дописываем в файл f целое число N, а точнее 2 блока по
//одному байту из переменной N.
BlockWrite ( f,N, sizeof ( word ) );
//Дописываем в файл f целое число P, а точнее 2 блока по
//одному байту из переменной P.
BlockWrite ( f, P, sizeof ( word ) );
for i :=1 to N do
for j :=1 to P do
//Записываем в файл f вещественное число C[i,j], а точнее
//sizeof(real) блоков по одному байту из переменной C[i,j].
BlockWrite ( f, c [ i, j ], sizeof ( real ) );
end
else
writeln ( ’Умножение невозможно ’ );
//Закрываем файл.
CloseFile ( f ); end.
< Лекция 6 || Лекция 7: 12345 || Лекция 8 >
Юрий Шутиков
Юрий Шутиков

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

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

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