По первому тесту выполнил дважды задания. Результат получается правильный (проверял калькулятором). Пишет, что "Задание не проверено" и предлагает повторить. |
Обработка файлов средствами Free Pascal
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.
Для того чтобы записать данные в файл, необходимо выполнить следующее:
- Описать файловую переменную.
- Связать её с физическим файлом (процедура AssignFile).
- Открыть файл для записи (процедура rewrite).
- Записать данные в файл (процедура write).
- Обязательно закрыть файл (процедура CloseFile).
Рассмотрим создание компонентного файла на примере решения следующей несложной задачи.
Алгоритм решения задачи состоит из следующих этапов:
- Открыть файл для записи с помощью оператора rewrite.
- Ввести значение n.
- В цикле (при i, меняющемся от 1 до n) ввести очередное вещественное число a, которое сразу же записать в файл с помощью процедуры write.
- Закрыть файл с помощью процедуры 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 начнём со знакомства с компонентом OpenDialog. Этот компонент предназначен для создания стандартного диалогового окна выбора файла и расположен первым на странице Dialogs (см. рис. 7.1).
Среди основных свойств этого компонента можно выделить:
- FileName: String — полное имя выбранного пользователем файла;
- Filter: String — строка, которая возвращает фильтры отбираемых файлов; это свойство можно задать с помощью редактора фильтров или с помощью специальной строки.
Для вызова редактора необходимо щёлкнуть по кнопке (свойства Filter), после чего появится окно редактора фильтров (см. рис. 7.2).
Окно редактора фильтров состоит из двух столбцов: Filter name — имя фильтра (например, все файлы — программы Паскале); Filter — соответствующая имени фильтра маска (фильтру "все файлы" соответствует маска "*.*", фильтру "программы на Паскале" — маска "*.pas".
Специальная строка состоит из последовательных имен фильтров и соответствующих им масок, разделённых символом "|". Специальная строка, соответствующая фильтру, представленному на рис. 7.2, имеет вид:
OpenDialog1. Filter := ’Программы_на_C|*.c|Программы_на_Паскале|*.pas|Все_файлы|*.*’;
Первый фильтр в списке является фильтром по умолчанию, в примере на рис. 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. Можно выделить следующие этапы решения задачи.
- Выбор файла.
- Чтение данных из файла в массив вещественных чисел.
- Удаление в массиве вещественных чисел всех чисел, меньших среднего арифметического, расположенных между максимальным и минимальным элементами.
- Запись преобразованного массива в файл.
Разработку программы начнём с создания графического приложения (Проект — Создать Проект — Приложение).
На форме расположим следующие компоненты:
- Две метки Label1 и Label2 для подписи.
- Memo1 — компонент, в котором будем хранить содержимое исходного файла.
- Memo2 — компонент, в котором будет храниться преобразованный файл.
- OpenDialog1 — компонент для выбора имени обрабатываемого файла.
- Button1 — кнопка для запуска программы.
- Button2 — кнопка для завершения программы.
Установим следующие свойства формы и компонентов (см. табл. 7.1, см. табл. 7.2, см. табл. 7.3, см. табл. 7.4, см. табл. 7.5, см. табл. 7.6, см. табл. 7.7, см. табл. 7.8).
Свойство | InitDialog | DefaultExt |
---|---|---|
Значение | /home/evgeniy/pascal/6/pr2/ | dat |
Свойство | Caption | Name | Visible |
---|---|---|---|
Значение | Преобразовать файл | Button_File | True |
Свойство | Caption | Name | Visible |
---|---|---|---|
Значение | Закрыть | Button_Close | False |
Расположим компоненты на форме подобно тому, как показано на рис. 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;
При щелчке по кнопке "Закрыть" программа должна завершать свою работу. Поэтому текст обработчика щелчка по кнопке будет очень простым.
procedure TForm_File. Button_CloseClick ( Sender : TObject ); begin Close; end;
Проверим функционирование созданного приложения. После запуска программы появляется окно, подобное представленному на рисунке 7.4. Щелчком по кнопке Преобразовать файл открывается диалоговое окно выбора файла (рисунок 7.5).
После щелчка по кнопке OK, окно программы становится похожим на представленное на рис. 7.6. Щелчок по кнопке Закрыть завершает работу приложения. Задача 7.2 решена, разработано функционирующее приложение.
В связи с тем, что файл — последовательная структура данных, при решении задачи пришлось целиком считывать содержимое файла в массив, проводить обработку данных в массиве и только затем записывать в файл. Такой метод не всегда удобен. Кроме того, при считывании данных из файла в массив мы ограничены описанием статического массива. Если в файле окажется больше элементов, чем при описании статического массива (в нашем случае > 100), то программа не будет правильно работать. Использование динамического массива не решит эту проблему, потому что неизвестно количество элементов в массиве.
Для решения этой проблемы в языке Free Pascal реализован прямой доступ к файлу с помощью рассмотренных далее подпрограмм работы с файлами.