Какой оператор осуществляет запись данных в файл
Перейти к содержимому

Какой оператор осуществляет запись данных в файл

  • автор:

Ввод данных из файла и вывод в файл

До этого при вводе-выводе данных мы работали со стандартными потоками — клавиатурой и монитором. Теперь рассмотрим, как в языке C реализовано получение данных из файлов и запись их туда. Перед тем как выполнять эти операции, надо открыть файл и получить доступ к нему.

В языке программирования C указатель на файл имеет тип FILE и его объявление выглядит так:

FILE *myfile;

С другой стороны, функция fopen() открывает файл по указанному в качестве первого аргумента адресу в режиме чтения («r»), записи («w») или добавления («a») и возвращает в программу указатель на него. Поэтому процесс открытия файла и подключения его к программе выглядит примерно так:

myfile = fopen("hello.txt", "r");

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

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

Если в силу тех или иных причин (нет файла по указанному адресу, запрещен доступ к нему) функция fopen() не может открыть файл, то она возвращает NULL. В реальных программах почти всегда обрабатывают ошибку открытия файла в ветке if , мы же далее опустим это.

Объявление функции fopen() содержится в заголовочном файле stdio.h, поэтому требуется его подключение. Также в stdio.h объявлен тип-структура FILE.

После того, как работа с файлом закончена, принято его закрывать, чтобы освободить буфер от данных и по другим причинам. Это особенно важно, если после работы с файлом программа продолжает выполняться. Разрыв связи между внешним файлом и указателем на него из программы выполняется с помощью функции fclose() . В качестве параметра ей передается указатель на файл:

fclose(myfile);

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

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

fscanf()

Функция fscanf() аналогична по смыслу функции scanf() , но в отличии от нее осуществляет форматированный ввод из файла, а не стандартного потока ввода. Функция fscanf() принимает параметры: файловый указатель, строку формата, адреса областей памяти для записи данных:

fscanf(myfile, "%s%d", str, &a); 

Возвращает количество удачно считанных данных или EOF. Пробелы, символы перехода на новую строку учитываются как разделители данных.

Допустим, у нас есть файл содержащий такое описание объектов:

apples 10 23.4 bananas 5 25.0 bread 1 10.3

Тогда, чтобы считать эти данные, мы можем написать такую программу:

#include int main () { FILE *file; struct food { char name[20]; unsigned qty; float price; }; struct food shop[10]; char i=0; file = fopen("fscanf.txt", "r"); while (fscanf(file, "%s%u%f", shop[i].name, &(shop[i].qty), &(shop[i].price)) != EOF) { printf("%s %u %.2f\n", shop[i].name, shop[i].qty, shop[i].price); i++; } }

В данном случае объявляется структура и массив структур. Каждая строка из файла соответствует одному элементу массива; элемент массива представляет собой структуру, содержащую строковое и два числовых поля. За одну итерацию цикл считывает одну строку. Когда встречается конец файла fscanf() возвращает значение EOF и цикл завершается.

fgets()

Функция fgets() аналогична функции gets() и осуществляет построчный ввод из файла. Один вызов fgets() позволят прочитать одну строку. При этом можно прочитать не всю строку, а лишь ее часть от начала. Параметры fgets() выглядят таким образом:

fgets(массив_символов, количество_считываемых_символов, указатель_на_файл)
fgets(str, 50, myfile)

Такой вызов функции прочитает из файла, связанного с указателем myfile, одну строку текста полностью, если ее длина меньше 50 символов с учетом символа ‘\n’, который функция также сохранит в массиве. Последним (50-ым) элементом массива str будет символ ‘\0’, добавленный fgets() . Если строка окажется длиннее, то функция прочитает 49 символов и в конце запишет ‘\0’. В таком случае ‘\n’ в считанной строке содержаться не будет.

#include #define N 80 main () { FILE *file; char arr[N]; file = fopen("fscanf.txt", "r"); while (fgets(arr, N, file) != NULL) printf("%s", arr); printf("\n"); fclose(file); }

В этой программе в отличие от предыдущей данные считываются строка за строкой в массив arr. Когда считывается следующая строка, предыдущая теряется. Функция fgets() возвращает NULL в случае, если не может прочитать следующую строку.

getc() или fgetc()

Функция getc() или fgetc() (работает и то и другое) позволяет получить из файла очередной один символ.

#include #define N 80 int main () { FILE *file; char arr[N]; int i; file = fopen("fscanf.txt", "r"); while ((arr[i] = fgetc(file)) != EOF) { if (arr[i] == '\n') { arr[i] = '\0'; printf("%s\n",arr); i = 0; } else i++; } arr[i] = '\0'; printf("%s\n",arr); fclose(file); }

Приведенный в качестве примера код выводит данные из файла на экран.

Запись в текстовый файл

Также как и ввод, вывод в файл может быть различным.

  • Форматированный вывод. Функция fprintf ( файловый_указатель, строка_формата, переменные ) .
  • Посточный вывод. Функция fputs ( строка, файловый_указатель ) .
  • Посимвольный вывод. Функция fputc() или putc( символ, файловый_указатель ) .

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

Запись в каждую строку файла полей одной структуры:

#include int main () { FILE *file; struct food { char name[20]; unsigned qty; float price; }; struct food shop[10]; char i=0; file = fopen("fprintf.txt", "w"); while (scanf("%s%u%f", shop[i].name, &(shop[i].qty), &(shop[i].price)) != EOF) { fprintf(file, "%s %u %.2f\n", shop[i].name, shop[i].qty, shop[i].price); i++; } fclose(file); }

Построчный вывод в файл ( fputs() , в отличие от puts() сама не помещает в конце строки ‘\n’):

while (gets(arr) != NULL) { fputs(arr, file); fputs("\n", file); }

Пример посимвольного вывода:

while ((i = getchar()) != EOF) putc(i, file);

Чтение из двоичного файла и запись в него

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

При открытии файла для двоичного доступа, вторым параметром функции fopen() является строка «rb» или «wb».

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

Функции fread() и fwrite() принимают в качестве параметров:

  1. адрес области памяти, куда данные записываются или откуда считываются,
  2. размер одного данного какого-либо типа,
  3. количество считываемых данных указанного размера,
  4. файловый указатель.

Эти функции возвращают количество успешно прочитанных или записанных данных. Т.е. можно «заказать» считывание 50 элементов данных, а получить только 10. Ошибки при этом не возникнет.

Пример использования функций fread() и fwrite() :

#include #include int main () { FILE *file; char shelf1[50], shelf2[100]; int n, m; file = fopen("shelf1.txt", "rb"); n=fread(shelf1, sizeof(char), 50, file); fclose(file); file = fopen("shelf2.txt", "rb"); m=fread(shelf2, sizeof(char), 50, file); fclose(file); shelf1[n] = '\0'; shelf2[m] = '\n'; shelf2[m+1] = '\0'; file = fopen("shop.txt", "wb"); fwrite(strcat(shelf2,shelf1), sizeof(char), n+m, file); fclose(file); }

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

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

Курс с решением части задач:
pdf-версия

Подготовка к олимпиадам по информатике

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

Ввод мы будем осуществлять из файла input.txt

Вывод будем производить в файл output.txt


Для организации ввода данных из файла надо:

1.Связать текстовый файл для чтения исходных данных с input:

assign(input,’input.txt’).

2. Открыть файл для чтения:
reset(input);

3. При работе нужно понимать и помнить отличия процедуры read, от readln. Если в файле данные записаны в одной строке, через пробел, то мы пользуемся все время процедурой read столько раз, сколько чисел нужно прочитать.
Если же строк несколько, то когда доходим до символа стоящего в конце строки, используем readln. В результате чего будет считано последнее число строки и курсор переместится на новую.
read(a); readln(a);

Например, указан следующий формат ввода:

В первой строке ввода находятся три числа через пробел R – радиус основания торта, N – число коробок, С – стоимость за 1 см 2 основания коробки.

Далее идет N строк, в каждой указаны два числа – длины сторон i -той коробки.
В программе записываем:
read(r,n,c);
for i:=1 to n do readln(x[i],y[i]);
4. Как только все переменные прочитаны необходимо закрыть файл.
close(input);

Для организации вывода данных в файл надо:

1.Связать текстовый файл для записи результатов с output:

assign(output,’output.txt’).

2. Открыть файл для записи:
rewrite(output);

3.Для вывода используем операторы write и writeln также, как и было до сих пор.

4. Как только все переменные выведены необходимо закрыть файл.
close(output);

Задание 1. Перенаправление. Прочитайте число n из файла input.txt и выведите его в файл output.txt

Входные данные:
В единственной строке входного файла input.txt записано число.
Выходные данные:
В единственную строку выходного файла output.txt нужно вывести в точности то же число, которое задано во входном файле.

Program z1;
var a:longint;
Begin
assign(input,’input.txt’);
reset(input);
read(a);
close(input);
assign (output,’output.txt’);
rewrite(output);
writeln(a);
close(output);
End.

Экспериментальный раздел

Наберите программу в среде программирования Free Pascal, запустите ее на исполнение. У Вас может появится ошибка типа:
exited with exitcode=2 (для Free Pascal), если файла input.txt нет.

Создайте в папке, где сохранена ваша программа файл input.txt и введите в него число.

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

Создание входного файла
Нажать F3, в открывшемся окне диалога Открыть файл написать имя входного файла (например, input.txt).
Если файл не существовал, среда Паскаля откроет пустое окошко с нужным именем. Ввести данные.
Не забыть нажать F2 — сохранить изменения.

Открытие входного и выходного файлов
Переместить курсор на строку в одиноч­ных кавычках, содержащую имя файла, например ‘input.txt’ в операторе assign.
Нажать Ctrl+Enter.
После изменения входных данных не забыть сохра­нить файл — F2.

Переход между окнами входных, выходных данных и текстом программы осуществляется нажатием клавиши F6.

Входные данные:
В первой строке входного файла содержится единственное число А, (0 <А<=32000).
Во второй строке входного файла содержится единственное число В, (0<В<=32000).

Выходные данные:
В единственную строку выходного файла вывести сумму этих чисел.
Тесты Посмотреть решение

Входные данные:
Первая строка входного файла содержит число А.
Вторая строка входного файла содержит число В.
(0

Выходные данные:
В первой строке выходного файла должно быть число В.
Во второй строке выходного файла число А.
Тесты Посмотреть решение

Задание 4. Имеется текстовый файл на 10 строк. Вывести на экран:
а) его первую строку;
б) его пятую строку;
в) его первые 5 строк;
г) его строки с s1-й no s2-ю (s1 и s2 записаны в 11 строке входного файла через пробел);
д) весь файл.



Тесты Посмотреть решение

Задание 5. Сформируйте массив целых чисел (значения для него взять из файла, они записаны во 2-ой строке входного файла). В первой строке этого файла указано количество элементов массива (n <=50). Вывести в выходной файл количество отрицательных чисел массива, его наименьшее и наибольшее значения.

Входные данные:
В первой строке входного файла содержится единственное число n — количество элементов массива

Во второй строке входного файла содержатся N чисел через пробел — элементы массива

Выходные данные:
Первая строка — количество отрицательных элементов массива

Вторая строка — наименьший элемент массива
Третья строка — наибольший элемент массива

Тесты Посмотреть решение

Задание 6. Имеются два текстовых файла, состоящие из одной строки. Переписать строку первого файла во второй, а строку второго файла — в первый. Использовать вспомогательный файл.


Program z6;
var s,t:string;
Begin
assign(input,’t1.txt’);
reset(input);
read(s);
close(input);

assign(input,’t2.txt’);
reset(input);
read(t);
close(input);

assign (output,’t.txt’);
rewrite(output);
writeln(s);
close(output);

assign (output,’t1.txt’);
rewrite(output);
writeln(t);
close(output);

assign(input,’t.txt’);
reset(input);
read(s);
close(input);

assign (output,’t2.txt’);
rewrite(output);
writeln(s);
close(output);
End.

Тесты Посмотреть решение


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

Входные данные:

Для каждого входного файла
Первая строка содержит число n — количество строк
Вторая строка — n-ая строки содержат текст

Выходные данные:
Для каждого выходного файла
Первая строка — n-ая строка содержат текст

Тесты Посмотреть решение

Задание 8. Даны три целых числа. Определить, имеется ли среди них хотя бы
одна пара равных между собой чисел.


Входные данные:
Первая строка содержит три целых числа через пробел.
Выходные данные:
Выведите ‘YES’ если это так, и ‘NO’ в противном случае.

Тесты Посмотреть решение

Задание 9. Даны три числа. Определить, существует ли треугольник, сторонами которого являются эти числа, и если существует, найти его площадь.

Замечание: треугольник существует, если каждая сторона меньше суммы двух других сторон. Площадь треугольника равна sqrt(p*(p-a)*(p-b)*(p-c)), где р — полупериметр, a,b,c — стороны треугольника.

Входные данные:
Первая строка содержит три числа через пробел.

Выходные данные:
В первой строке запись «да» или «нет»
Во второй строке значение площади, если треугольник существует

Тесты Посмотреть решение

Задачи для самостоятельного решения

1. Создайте текстовый файл на диске, заполненный N целыми числами, записанными через пробел.
а) Выведите на экран сумму этих чисел, среднее арифметическое и произведение;
б) то же вывести в файл в отдельные строки.

2. Дан файл, заполненный целыми числами через пробел. Вывести в новый файл все:
а) четные числа;
б) числа, делящиеся на 3 и не делящиеся на 7.

3. Имеется текстовый файл, состоящий из n строк, записанных в столбик. Переписать его строки в другой файл. Порядок строк во втором файле должен:
а) совпадать с порядком строк в заданном файле;
б) быть обратным по отношению к порядку строк в заданном файле.

4. Имеется текстовый файл, состоящий из n строк, записанных в столбик. Все четные строки этого файла записать во второй файл, а нечетные — в третий файл. Порядок следования строк сохраняется.

Теоретический материал: файловый ввод-вывод (Паскаль)

Файлы. Виды файлов. Основные процедуры для работы с файлами

До сих пор мы рассматривали задачи, в которых во время выполнения программы данные поступают с клавиатуры, а результаты выводятся на экран дисплея. При этом ни исходные данные, ни результаты не сохраняются. Всякий раз при выполнении одной и той же программы, в частности, во время отладки, приходится заново вводить данные. А если их очень много? В языке Паскаль есть возможность записать их на диск. Для этого необходимо оформить исходные данные и результаты в виде файлов, которые хранятся на диске точно так же, как и программы.

Понятие файла — это фундаментальное понятие информатики, вспомним же его определение.

Определение. Файлом называется область памяти на диске, имеющая свое имя.

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

Физические файлы можно по-разному представить в программе. Язык Турбо Паскаль предлагает три вида представления файлов:

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

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

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

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

С каждым файлом можно связать понятие «текущий указатель». Это неявно описанная переменная, которая указывает на конкретный элемент файла. Действия с файлами производятся поэлементно, причем в них участвует тот элемент, на который «смотрит» текущий указатель, перемещающийся в результате выполнения действия на следующий элемент.

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

— описать переменную файлового типа;

— связать ее с конкретным физическим файлом процедурой assign;

— открыть файл процедурой reset или rewrite;

— выполнить чтение или запись информации;

— по окончании работы с файлом закрыть файл процедурой close.

Формат объявления файловых переменных и особенности работы с различными видами файлов (типизированными, нетипизированными, текстовыми) будут подробно изложены далее.

Процедуры и функции для работы с файлами любого типа

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

Сначала рассмотрим процедуры модуля System.

Напомним, что он подключен к программам по умолчанию, то есть его не требуется подключать к программе в разделе Uses.

До начала работы с файлами устанавливается связь файловой переменной МуFilе с именем дискового файла. Очень важно различать собственно файл (область памяти на магнитном носителе с некоторой информацией) и переменную файлового типа в Turbo Pascal-программе. Считается, что файловая переменная является представителем некоторого дискового файла в программе. Для того, чтобы реализовать доступ к файлу на магнитном диске, программа должна связать его с файловой переменной. Для этого необходимо установить соответствие между переменной и именем файла. Это имя представляется в виде строки, содержащей имя файла и, может быть, путь к файлу, который формируется по общим правилам MS-DOS.

assign (МуFilе, ‘с:\МуDirectory\Result.dat’);

здесь приведено полное (с указанием пути) имя пользовательского файла Result.dat.

Если путь не указан, программа будет искать файл только в своем рабочем каталоге и, как это принято в системе DOS, по указанным в файле аutoехес.bat путям. Кроме указания имени файла на дисковом накопителе может быть указано стандартное имя одного из устройств ввода-вывода: «соn» — консоль, то есть дисплей и клавиатура, «рrn» — или «lpt1» — принтер.

Не разрешается связывать с одним физическим файлом разные файловые переменные программы.

До тех пор, пока файловая переменная не связана с каким-либо дисковым файлом, никакие операции с ней в программе невозможны. Заметим, что можно связать файловую переменную с еще не существующим дисковым файлом. Это делается в случае последующего создания Turbo Pascal-программой файла с данным именем с помощью специальной системной процедуры.

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

Внимание! Нельзя применять процедуру assign к открытому файлу.

Все файлы, открытые в результате работы программы, должны быть закрыты при завершении программы процедурой

closе (МуFilе);

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

Открытие нового файла производится процедурой, единственный аргумент которой — переменная файлового типа, например:

rewrite (МуFilе);

Эта процедура создает на диске файл с именем, связанным с переменной МуFilе процедурой Аssign. Указатель работы с файлом устанавливается на начало файла. После выполнения процедуры rewrite файл доступен как для записи, так и для чтения (в случае текстовых файлов – только для записи).

Внимание! Если файл с таким именем уже существует, он удаляется (его содержимое теряется), и создается новый пустой файл с данным именем.

Открытие существующего файла выполняет процедура

reset (МуFilе);

Эта процедура ищет уже существующий файл на диске и открывает его для работы, помещая указатель в начальную позицию. Если файл с установленным в Аssign именем не найден, возникает ошибка ввода/вывода, контроль которой зависит от директивы компилятора (смотрите здесь). После выполнения процедуры reset файл доступен как для записи, так и для чтения (в случае текстовых файлов – только для чтения).

Запись в файл производится процедурой

write (МуFilе, var1, var2, . varN);

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

Чтение из файла производится аналогичной процедурой:

read (МуFilе, var1, var2, . varN);

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

Положение элементов в файле нумеруется, начиная с номера 0 для первого элемента. После последнего элемента файла автоматически записывается признак конца файла.

Функция FileSize(МуFilе) определяет число элементов в файле. Функция неприменима к текстовым файлам. Файл MyFyle должен быть открыт.

Функция логического типа ЕОF(МуFilе) имеет значение Тruе, если указатель указывает на маркер конца файла (End Of File).

Типизированные файлы

Определение. Типизированный файл — последовательность элементов одного типа. Таким образом, типизированный файл Вы можете представить себе как цепочку однотипных данных. Все компоненты файла имеют общее имя, а каждый – еще и свой номер. Начальный элемент имеет нулевой номер. Длина файла, то есть количество элементов в цепочке — величина произвольная, изменяемая в процессе работы. После последнего элемента автоматически записывается признак конца файла. Описание файлового типа для работы с типизированным файлом имеет синтаксис:

file of < тип элементов>;

Допустим, мы имеем дело с файлом, в котором записываются переменные типа Word, тогда переменная файлового типа может быть введена двояко – с явным объявлением файлового типа:

Type
WordFile = file of word;
Var
MyFile : WordFile;

или без объявления файлового типа:

Var
MyFile : file of word;

Приведем примеры переменных файлового типа с другими объявлениями:

Type
Student = record
Name, SurName : string;
YearsOld : byte;
Sessia : array [1..10] of byte;
end;
Var
VarFile1 : file of char;
VarFile2 : file of Student;
VarFile3 : file of string;

Напомним, что файловые переменные имеют специфическое применение: их можно использовать только для выполнения операций с файлами (чтения, записи, удаления файла и т.д.) и получения информации о конкретном файле (тип, параметры, имя файла и т.д.). Работа с файлами заключается в записи и считывании его компонентов. Для того, чтобы определить, какие данные будут участвовать в операции, используется неявно заданная переменная – указатель на текущий элемент файла. При открытии файла процедурами reset, rewrite указатель устанавливается на его начало. Запись и чтение производятся поэлементно, причем в них участвует тот элемент файла, на который «смотрит» указатель. В результате выполнения действия указатель перемещается к следующему элементу. Пример. Приведем шаблон программы для записи данных в типизированный файл.

Program Writing;
Var
FileName : string;
FVar : file of byte;
Index : byte;
Begin
write (‘Введите имя файла ‘);
readln (FileName);
assign (FVar, FileName);
rewrite (FVar);
for Index := 0 to 99 do
write (FVar,Index);
close (FVar);
End.

Примечание. В цикле могут быть вычислительные процедуры для получения данных, выводимых в файл. Мы, для простоты, записали в файл счетчик цикла. Внимание! Следует запомнить, что процедура rewrite очистит файл, если файл с таким именем уже есть в рабочем каталоге, поэтому при выборе имен файлов соблюдайте осторожность. Задание 1. Наберите предложенную выше программу и дополните ее выводом на экран элементов файла (воспользуйтесь процедурой считывания из файла read и вывода на экран write). Задание 2. Создайте программу записи и чтения типизированного файла типа string.

Примеры решения задач

    нахождением среднего стажа работы в институте;

Процедуры и функции для работы с типизированными файлами

Вспомним, что типизированный файл — это линейная последовательность элементов одного типа. При каждом обращении к файлу (чтении, записи) его текущий указатель перемещается к следующему элементу. Возникает вопрос: можно ли нарушить порядок доступа к элементам файла и, например, не считывая из файла первый и второй элемент, сразу обратиться к третьему? Оказывается, можно.

Для изменения теущего положения указателя используется процедура

Seek (МуFilе, n);

где n — требуемое положение указателя.

Внимание! Нумерация элементов типизированного файла начинается с нуля.

Следовательно, для обращения к третьему элементу нужно записать: Seek (МуFilе, 2).

Seek (МуFilе, 0) — устанавливает указатель в начальную позицию (на первый элемент).

Seek (МуFilе, FileSize(МуFilе)) — устанавливает указатель после последнего элемента, то есть на признак конца файла.

Примечание. Функция FileSize(МуFilе) возвращает количество элементов типизированного файла МуFilе.

Текущую позицию указателя дает функция

FilePos (МуFilе);

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

Рrogram Writing;
Var
FileName : string;
FVar : file of char;
Index : integer;
Letter : char;
Begin
write(‘Enter filename: ‘);
readln (FileName);
assign (FVar,FileName);

reset (FVar);

if IOResult <> 0
then
begin
writeln (‘Не открыт файл ‘, FileName);
Halt
end;
while not EOF (FVar) do
begin
read (FVar, Letter);
Letter:=Upcase(Letter);
Seek(FVar,FilePos(FVar)-1);
write(FVar,Letter);
end;
close(FVar)
End.

Функция IOResult

Как Вы уже заметили, в предыдущей программе была использована функция IOResult. Рассмотрим, какую роль выполняет эта функция.

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

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

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

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

reset (F,’C:\TP7\BIN\Text.txt’);
if IOResult <> 0
then
writeln (‘Ошибка при открытии файла’);

В своих программах Вы должны применять функцию IOResult.

Замечание. Функция применима к операциям файлового ввода/вывода независимо от вида файла (типизированный, нетипизированный, текстовый).

Решение задач

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

Program Files;
Uses
Crt;
Var
F, Fnew : file of string;
Name, NewName : string[12];
Str : string;
Ch : char;
Procedure ReadText;
Begin
repeat
write(‘Введите имя файла>’);
readln(Name);
assign(F, Name);
reset(F);
if IOresult<>0
then
begin
writeln(‘Ошибка чтения’);
close(F);
end;
until IOresult=0;
writeln(‘Содержание файла ‘, Name,’:’);
while not Eof(F) do
begin
read(F, Str);
writeln(Str);
end;
close(F);
End;
Procedure EraseFile;
Begin
erase(F);
writeln(‘Файл удален’);
End;
Procedure ReNameFile;
Begin
write(‘Введите новое имя файла:’);
readln(NewName);
rename(F, NewName);
writeln(‘Файл ‘, Name,’ переименован в файл ‘, NewName);
End;
Procedure CopyFile;
Begin
write(‘Введите имя копии файла ‘, Name,’>’);
readln(NewName);
reset(F);
assign(Fnew, NewName);
rewrite(Fnew);
while not Eof(f) do
begin
read(F, Str);
write(Fnew, Str);
end;
close(F);
close(Fnew);
writeln(‘Файл’, Name,’ скопирован в файл ‘, NewName);
End;
Begin
ClrScr;
readTеxt;
repeat
writeln(‘Удаление файла (D),переименование файла(R)’);
writeln(‘Копирование файла (C), выход из программы (Е)’);
write(‘Введите символ нужной операции — ‘);
readln(ch);
case ch of
‘D’,’d’: EraseFile;
‘R’,’r’: ReNameFile;
‘C’,’c’: CopyFile;
end;
until (ch=’E’) or (ch=’e’);
readln;
End.

Тeкстовые файлы, их описание и основные отличия от типизированных файлов

  • значения целого типа;
  • значения вещественного типа;
  • значения булевского типа.

Для записи произвольной информации в текстовый файл в языке имеются дополнительные возможности, которые заключаются в задании размера поля записи. Если после записываемой переменной или выражения поместить символ двоеточия, а после него — любое выражение целого типа, то для выводимого значения будет отведено поле, размер которого (число символов) будет равен значению выражения. Следующая тривиальная программа наглядно показывает действие указателя поля:

Program TextFile3;
Var
f : text;
V : real;
i : word;
Put : string;
Begin
Put := ‘D:\TP7\BIN\Primer3’;
assign(f, Put);
rewrite(f);
V := 123.456;
write(f, V,#13#10);
for i := 10 to 14 do
write(f, V:i,#13#10);
close(f);
End.

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

Управление размещением значений в текстовых файлах очень удобно использовать при формировании структурированных файлов (списков, таблиц и т.п.). Если количество позиций, занимаемых выводимым значением меньше размера поля, то значение всегда «прижимается» к правому краю поля.

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

Способы обмена с текстовыми файлами

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

Операции чтения из файла

reset(f) — открывает существующий файл на чтение. Файловая переменная должна быть связана с внешним файлом с помощью процедуры assign.

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

Если f соответствует пустое имя файла (например, после вызова assign(f, »)), то после обращения к процедуре Reset(f) будет использоваться стандартный файл ввода (канал 0).

Текстовый файл становится доступным только на чтение.

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

read( [f : text], v1 [, v2, . vn] ) — читает из текстового файла значения одной или более переменных.

Если параметр f не указан, то подразумевается использование стандартной файловой переменной Input. Каждый параметр v является переменной, значение которой должно быть прочитано из файла.

readln( [f : text], [v1, v2, . vn] ) — выполняет процедуру read, затем переходит к следующей строке файла.

Процедура readln является расширением процедуры read и определена для текстовых файлов. Вызов readln(f) с указанием одного параметра-файловой переменной приводит к перемещению текущей позиции файла на начало следующей строки, если она имеется, в противном случае происходит переход к концу файла. Процедура readln без параметров полностью соответствует стандартному вводу.

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

Примечание: Процедура работает только для текстовых файлов, включая стандартный ввод. Файл должен быть открыт для ввода.

Процедура readln является очень удобным аналогом read. В случае использования readln после чтения из файла очередной порции символов (и, быть может, преобразования их в значение подходящего типа) текущий указатель файла будет перемещен на начало его следующей строки. Иными словами, остаток строки, расположенный в файле после прочитанного значения, будет пропущен.

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

Операции записи в файл

rewrite(f) — cоздаёт и открывает новый файл. Файловая переменная должна быть связана с внешним файлом с помощью процедуры assign.

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

Если f соответствует пустое имя файла (например, после вызова assign(f, »)), то после обращения к процедуре rewrite(f) будет использоваться стандартный файл вывода (канал 1).

Текстовый файл становится доступным только на запись.

write( [f : text], v1 [, v2, . vn] ) — записывает значения одной или более переменных в текстовый файл.

Если параметр f не указан, то подразумевается использование стандартной файловой переменной Output. Каждый параметр v является выражением, значение которого должно быть записано в файл. Выводимое выражение должно быть символьного, целого, вещественного, строкового или булевского типа.

Параметр v может иметь вид:

Var
a:real;
. . . . . . .
write(f, a: 5: 2);

Такая запись означает, что мы в файл записываем действительное (не целое) число а, размером 5 знаков, 2 знака под дробную часть.

writeln( [f : text], [v1, v2, . vn] ) — выполняет процедуру write, а затем записывает в файл метку конца строки (перевод строки).

При вызове данной процедуры с указанием только параметра-файловой переменной: writeln(f), в файл записывается метка конца строки. Процедура writeln без параметров полностью соответствует стандартному выводу на экран.

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

Логическая функция Eoln

Часто для обработки текстовых файлов используется специфичная для них функция Eoln, позволяющая определить, достигнут ли конец строки. Если достигнут — значение функции равно True, а если нет — False. Таким образом, для анализа конкретных символов строк файла можно применить вложенный цикл типа:

while not Eof(FileName) do
while not Eoln(FileName) do
begin

end;

Процедура открытия файла для дополнения

append(f : Тext) — процедура открывает существующий файл для дозаписи. Если файл уже открыт, то он сначала закрывается, а затем открывается заново. Текущая позиция устанавливается на конец файла.

Если в последнем блоке файла размером 128 байтов присутствует символ Сtrl+Z (26 в коде ASCII), то текущая позиция устанавливается в файле таким образом, что при записи первым в блоке будет «затираться» символ Сtrl+Z.

Если переменной f соответствует пустое имя файла (например, после вызова assign(f, »)), то после обращения к процедуре append переменная f будет указывать на стандартный выходной файл.

После обращения к append файл f становится доступным только на запись, и Eof(f) принимает всегда значение True(истина).

Рассмотрите несколько примеров простых программ.

Program TextFile4;

Var
f, t: text;
Put1, Put2, d: string;
s : char;
Begin
Put1 := ‘D:\TP7\BIN\Primer1’;
assign(f, Put1 );
reset(f);
Put2 := ‘D:\TP7\BIN\Primer2’;
assign(t, Put2);
rewrite(t);
while Not Eof(f) Do
begin
while Not Eoln(f) do
begin
read(f, s);
write(t, s);
end;
readln(f);
writeln(t);
end;
close(t);
close(f);
End.

Program TextFile5;

Var
f : Text;
Put, s : string;
a, i : integer;
Begin
a := 0;
Put := ‘D:\TP7\BIN\Primer2’;
assign(f, Put);
reset(f);
while Not Eof(f) do
begin
readln(f, s);
for i := 1 to Length(s) do
begin
if s[i] = ‘(‘
then
Inc(a,1);
if s[i] = ‘)’
then
Dec(a,1);
end;
end;
close(f);
if a <> 0
then
writeln(‘No’)
else
writeln(‘Yes’);
readln
End.

Program TextFile6;

Var
f: text;
Begin
assign(f, ‘text.txt’);
rewrite(f); < Открыть файл c файловой пер. f на создание и запись>
writeln(f, ‘Исходный текст’); < Записывать в него cтроку>
close(f);
append(f);
writeln(f, ‘Добавляемый текст’); < Пишем в конец файла cтроку>
close(f);
End.

Стандартные текстовые файлы Input и Output. Примеры задач

В Паскале существуют два стандартных текстовых файла: Input и Output. Эти файлы считаются известными в любой Pascal-программе (иными словами, они описаны в стандартном модуле System). Они обозначают (по терминологии MS-DOS), соответственно, стандартный файл ввода и стандартный файл вывода. Обычно эти стандартные файлы связаны с конкретными физическими устройствами компьютера. Так, файловая переменная Input связана с клавиатурой, файловая переменная Output — с экраном дисплея. Эти файлы считаются заранее открытыми, а соответствующие идентификаторы можно использовать в операциях ввода-вывода.

Рассмотрим, например, следующий оператор:

writeln (Output, ‘Результат равен ‘, (X+Y)*2);

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

Аналогично, оператор read (Input, X1, X2); будет выполняться таким образом: система перейдет в состояние ожидания ввода с клавиатуры двух значений. Типы вводимых значений должны совпадать с типами переменных Х1 и Х2. Эти значения при вводе должны отделяться друг от друга одним или несколькими пробелами, а ввод должен быть завершен нажатием клавиши Enter. В процессе ввода значений набираемые на клавиатуре символы отображаются на экране. После нажатия Enter введенные значения будут присвоены переменным Х1 и Х2, и выполнение программы будет продолжено.

Для стандартных файлов Input и Output допускается сокращенная форма записи операций ввода-вывода. Так, если в процедурах read и readln первый параметр опущен, то по умолчанию подразумевается файл Input. Аналогично, отсутствие в процедурах write и writeln первого параметра означает вывод в стандартный файл Output. Вывод в стандартный файл Output используется очень часто — всегда, когда необходимо выдать некоторую информацию из программы на экран.

В соответствии с общими правилами MS-DOS стандартные файлы ввода-вывода могут быть «переназначены», то есть, связаны с другими физическими устройствами или дисковыми файлами. Простейшим способом переназначения является использование для этой цели процедуры assign, например,

assign (Output,’MyFile.out’);

После выполнения такого оператора стандартный файл вывода будет переназначен, то есть файловая переменная Output будет связана с дисковым файлом MyFile.out из текущего каталога. Все операции вывода, явно или неявно работающие с файлом Output, будут выводить информацию в указанный дисковый файл.

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

Program StringCount;
Uses
Crt;
Var
i : integer;
s : string;
f : text;
Begin
ClrScr;
readln(s);
assign(f, s);
reset(f);
i := 0;
while not Eof(f) do
begin
readln(f,s);
i:=i+1;
end;
close(f);
writeln(i);
readln;
End.
Program Zamen;
Uses
Crt;
Var
s : string;
f, d : text;
Begin
ClrScr;
readln(s);
assign(f, s);
readln(s);
assign(d, s);
reset(f);
rewrite(d);
while not Eof(f) do
begin
readln(f, s);
while Pos(‘o’, s)>0 do
s[Pos(‘o’, s)] := ‘a’;
writeln(d, s);
end;
close(f);
close(d);
readln;
End.
Program MaxInFile;
Uses
Crt;
Var
i, j, r, Code : integer;
s : string;
f : text;
Begin
ClrScr;
readln(s);
assign(f, s);
reset(f);
while not Eof(f) do
begin
readln(f, s);
j:=0;
for i:=1 to Length(s) do
begin
Val(s[i], r, Code);
if r>j
then
j:=r;
end;
writeln(j);
end;
close(f);
readln;
End.

Нетипизированные файлы. Их особенности. Процедуры blockread и blockwrite

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

Нетипизированный файл рассматривается в Паскале как совокупность символов или байтов. Выбор char или byte не играет никакой роли, важен лишь объем занимаемых данных.

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

Для определения в программе нетипизированного файла служит зарезервированное слово file:

Var
MyFile : file;

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

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

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

rewrite(MyFile, 1) или reset(MyFile, 1)

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

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

rewrite(MyFile) или reset(MyFile)

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

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

Во-первых, для обеспечения максимальной скорости обмена данными следует задавать длину, которая была бы кратна длине физического сектора дискового носителя информации (512 байт).

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

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

При работе с нетипизированными файлами могут применяться следующие процедуры и функции, применимые к типизированным файлам:

assign (МуFilе, ‘с:\МуDirectory\result.dat’) — процедура связывания логической файловой переменной МуFilе с конкретным физическим файлом на дисковом носителе информации;

closе (МуFilе) — процедура, закрывающая открытый файл;

rewrite (МуFilе) — процедура, создающая новый файл и открывающая его для записи и чтения; при работе с нетипизированными файлами эта процедура имеет дополнительный параметр, который был рассмотрен выше;

reset (МуFilе) — процедура, открывающая существующий файл данных для чтения и записи; при работе с нетипизированными файлами эта процедура имеет дополнительный параметр, который был рассмотрен выше;

eof (МуFilе) — логическая функция, проверяющая, достигнут ли конец файла;

seek (МуFilе, n) — процедура, позволяющая явно изменить значение текущего указателя файла, установив его на элемент с номером n;

filepos (МуFilе) — функция, возвращающая позицию указателя файла; нумерация начинается с нуля;

filesize(МуFilе) — функция, возвращающая количество элементов файла;

rename(МуFilе, FileName) — процедура, позволяющая переименовать существующий файл;

truncate(МуFilе) — процедура, позволяющая удалить часть существующего файла, начиная с текущей позиции и до конца файла;

erase(МуFilе) — процедура, стирающая указанный файл,

Вы должны были заметить, что в списке нет процедур read и write. Для чтения информации из нетипизированного файла и записи информации в него только для данного типа файлов в Турбо Паскаль введены две новые процедуры, поддерживающие операции ввода-вывода с более высокой скоростью.

Процедура BlockRead

blockread(Var F : file; Var Buf; Kol : word; result : word);

Процедура считывает из файла F определенное число записей в память, начиная с первого байта переменной Buf.

Параметр Buf представляет любую переменную, которая будет участвовать в обмене данными с дисками. Эту переменную нужно описать в программе так, чтобы ее размер не был меньше размера записи, установленного в параметрах rewrite или reset (как правило, для этих целей используется некоторый массив).

Параметр Kol задает число считываемых записей.

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

Использование параметра result подсказывает, что число считанных блоков может быть меньше, чем задано параметром Kol. Если result указан при вызове, то ошибки ввода-вывода в такой ситуации не произойдет. Для отслеживания этой и других ошибок чтения можно использовать опции , и функцию IOresult.

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

Процедура BlockWrite

blockwrite(Var F : file; Var Buf; Kol : word; result : word);

Процедура предназначена для быстрой передачи в файл F определенного числа записей из переменной Buf. Все параметры процедуры BlockWrite аналогичны параметрам процедуры BlockRead. Содержимое переменной Buf в количестве Kol записей помещается в файл, начиная с текущего положения указателя файла.

Обе процедуры выполняют операции ввода-вывода блоками. Объем блока в байтах определяется по формуле:

Объем = Kol * recSize,

где recSize — размер записи файла, заданный при его открытии. Суммарный объем разового обмена не должен превышать 64 Кбайт.

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

Возможна ситуация, когда при чтении в файле содержится менее Kol записей или в процессе записи на диске не окажется нужного свободного пространства. В этом случае, если параметр result в процедуре BlockRead (BlockWrite) не был задан, то возникнет ошибка ввода-вывода; в противном случае ошибка не будет зафиксирована, а после выполнения процедуры значение параметра result не совпадет со значением параметра Kol и будет равно количеству фактически прочитанных (записанных) записей. Последнее обстоятельство можно проверить, сравнив два указанных значения.

После завершения процедуры указатель смещается на result записей.

Рассмотрите примеры простых задач.

Задача 1. Составить программу, которая создает нетипизированный файл из 100 чисел и выводит на экран k-ый элемент.

Program Netipiz1;
Uses
Crt;
Type
FileType = file;
Var
f : FileType;
P, k : byte;
Begin
ClrScr;
assign(F, ‘MyFile’);
rewrite(F,1);
Randomize;
for k := 1 to 100 do
begin
P := Random(100);
blockwrite(F, P, 1);
end;
close(F);
reset(F,1);
for k := 1 to 100 do
begin
blockread(F, P, 1);
write(p,’ ‘);
end;
write(‘Введите номер нужного элемента ‘);
readln(k);
Seek(F, k-1);
blockread(F, P, 1);
writeln(k,’-ий элемент файла равен ‘, P);
close(F);
End.

Задача 2. Составить программу, которая создает копию элементов нетипизированного файла f и помещает в файл g.

Program Netipiz2;
Uses
Crt;
Var
f, g : file;
s : char;
Stroka1, Stroka2 : string;
Begin
ClrScr;
write(‘Введите имя исходного файла: ‘);
readln(Stroka1);
assign(f, Stroka1);
rewrite(f, 1);
writeln(‘Введите содержимое файла ‘);
readln(s);
while s <> #13 do
begin
blockwrite(f, s, 1);
readln(s);
end;
close(f);
reset(f, 1);
write(‘Введите имя конечного файла: ‘);
read(Stroka2);
assign(g, Stroka2);
rewrite(g, 1);
while not Eof(f) do
begin
blockread(f, s, 1);
blockwrite(g, s, 1);
end;
close(f);
close(g);
reset(g, 1);
writeln(‘Содержимое конечного файла:’);
while not Eof(g) do
begin
blockread(g, s, 1);
write(s);
end;
close(g);
readln;
End.

Задача 3. Составить программу, которая создает массив целых чисел и записывает его в нетипизированный файл, а также вычисляет среднее арифметическое элементов файла.

Program Netipiz3;
Uses
Crt;
Var
f : file;
i, k, s : integer;
Mas : Array [1..10] of byte;
Begin
ClrScr;
Randomize;
for i := 1 to 10 do
begin
Mas[i] := Random(10);
write(Mas[i]:3);
end;
assign(f, ‘file.dat’);
rewrite(f, 1);
blockwrite(f, Mas, 10);
close(f);
reset(f,1);
S:=0; i:=0;
while not Eof(f) do
begin
blockread(f, k, 1);
s:= s+k;
Inc(i);
end;
close(f);
writeln;
write(s/i:5:2);
readln;
End.

Задание. Наберите приведенные выше тексты программ, убедитесь в их работоспособности.

Использование текстовых файлов в качестве нетипизированных

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

Program Kodirovka;
Const
NofCod = 20;
Var
FirstFile : text;
SecondFile : file;
FirstName, SecondName : string;
IOres : byte;
NofSymb : LongInt;
Codes : Array[1..NofCod] of byte;
Buffer : Array [1..NofCod] of char;
i : word;
symbol : char;

Procedure WriteAndControl (Var Buf; Amount : word);
Var
result : word;
Begin
blockwrite (SecondFile, Buf, Amount, result);
if result <> Amount
then
begin
writeln(‘Нет места на диске ‘);
Halt;
end;
End;
Begin

repeat

write(‘Имя исходного файла: ‘);
readln(FirstName);
assign(FirstFile, FirstName);
reset(FirstFile);

IOres := IOresult;
if IOres <> 0
then
writeln(‘Такого файла нет ‘);
until IOres =0;

repeat

write(‘Имя результирующего файла: ‘);
readln(SecondName);
assign(SecondFile, SecondName);
rewrite(SecondFile, 1);

IOres := IOresult;
if IOres <> 0
then
writeln(‘Неправильное имя файла ‘);
until IOres =0;

NofSymb := 0;
WriteAndControl(NofSymb, 4);

Randomize;
for i := 1 to NofCod do
Codes[i] := Random(256);
WriteAndControl(Codes, NofCod);

i := 0;
while not Eof(FirstFile) do
begin
Inc(NofSymb);
Inc(i);
if Eoln(FirstFile)
then
begin
Buffer[i] := Chr((13+Codes[i]) mod 256);
if i=NofCod
then
begin
writeAndControl(Buffer, NofCod);
i := 0;
end;
Inc(i);
Buffer[i] := Chr((10+Codes[i]) mod 256);
readln(FirstFile);
end
else
begin
read(FirstFile, Symbol);
Buffer[i] := Chr((Ord(Symbol)+Codes[i]) mod 256);
end;
if i = NofCod
then
begin
writeAndControl(Buffer, NofCod);
i := 0;
end;
end;

if i <> 0
then
writeAndControl(Buffer, i);

NofSymb := FileSize(SecondFile)-NofCod-4;
Seek(SecondFile, 0);
writeAndControl(NofSymb, 4);

close(SecondFile);
close(FirstFile);
writeln(‘Конец работы программы ‘);
readln;
End.

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

Дополнительные процедуры и функции для работы с файлами

Рассмотрим три процедуры из модуля System.

Изменение имени файла производится процедурой

rename(МуFilе, FileName);

первый аргумент которой — переменная файлового типа, а второй аргумент — строкового типа — новое имя файла, которое может быть сокращенным или полным (с указанием пути). Действие этой процедуры эквивалентно действию аналогичной процедуры DOS.

Уничтожение части файла от текущего положения указателя до конца файла производится процедурой

truncate(МуFilе);

Процедура применима к любым типам файлов, кроме текстовых; файл должен быт предварительно открыт.

Уничтожение всего файла производится процедурой

erase(МуFilе);

действие которой эквивалентно удалению файла в операционной системе DOS. Процедура неприменима к открытым файлам.

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

Uses
Dos;

Ряд свойств файла, хранящегося на диске, кодируются так называемыми атрибутами. Атрибуты файла записываются не в сам файл, а в информационный раздел каталога, в котором хранится файл. Для хранения атрибутов отводится один байт, единица в определенном бите которого означает наличие свойства, а нуль — отсутствие. Соответствие битов и свойств показывает схема, приведенная на рисунке.

0 — Только чтение ReadOnly=1,

1 — Скрытый файл Hidden=2,

2 — Системный файл SysFile=4,

3 — Метка тома VolumeID=8,

4 — Подкаталог Directory=16,

5 — Архивный файл Archive=32,

Произвольный файл AnyFile=63.

Каждому атрибуту соответствует определенная константа, равная 2 k , где k — номер бита. Эти константы описаны в модуле Dos, их значения и имена приведены на схеме. В целом байт атрибутов образуется как сумма соответствующих ему констант. Установка атрибута «только чтение» приводит к невозможности изменения содержимого файла или его удаления.

Скрытые файлы игнорируются некоторыми командами операционной системы, в частности, они не показываются по команде Dir. Системные файлы — файлы операционной системы Dos. Атрибут «Архивный» означает, что для этого файла не была создана резервная копия командой BackUp.

Большинство файлов имеют этот атрибут. Определить атрибуты файла можно с помощью процедуры

GetFAttr(MyFile, Attr);

которая возвращает переменную Attr типа word, содержащую код атрибутов файла.

Например, проверить свойство «только для чтения» можно следующим образом:

GetFAttr(MyFile, Attr);
if Odd(Attr)
then
write (‘Только для чтения’)
else
write(‘Не только для чтения’);

Установка требуемых атрибутов файла производится процедурой

setFAttr (MyFile, Attr);

Процедуры для поиска на диске требуемых файлов используют специальный тип записи SearchRec, определенный в модуле Dos. Запись

Туре
SearchRec= record
Fill : аrrау [1..21] оf bytе;
Attr : bytе;
Time : longint;
Size : longint;
Name : string[12]
end;

Первое поле записи — массив Fill — используется операционной системой и не должно изменяться в пользовательских программах. Содержание поля Attr — атрибуты файла, рассмотренные выше. Поле Time содержит дату и время записи файла в упакованном виде, для распаковки служит процедура UnpackTime. Size — размер файла в байтах. Name — имя файла, включая разделительную точку и расширение.

FindFirst (SearchPath, Аttr, SearchResult);

ищет в каталоге первый файл, удовлетворяющий заданной спецификации. Параметры SearchPath и Аttr содержат исходные данные для поиска. Возвращаемый результат поиска — SearchResult — запись типа SearchRec. SearchPath — строка, содержащая полное имя файла, в том числе каталог, в котором необходимо искать файл, и имя файла. Имя файла (но не путь) может содержать символы звездочки и вопросительного знака, которые, соответственно, заменяют любую последовательность символов или один произвольный символ.

Если путь не приводится, поиск идет в рабочем каталоге. Следовательно, SearchPath = ‘*.dat’ указывает на все файлы с расширением «dat» в текущем каталоге.

Процедура FindNext(SearchResult) употребляется только после процедуры FindFirst и продолжает последовательно поиск файлов с определенным процедурой FindFirst шаблоном.

Функция FSearch(SearchString, DirList) ищет файл, заданный строкой SearchString, в заданном списке каталогов DirList. Список каталогов записывается так же, как в команде DOS Path, то есть различные каталоги разделены точкой с запятой. Результат этой функции — полное имя файла, если он найден по указанным путям.

Функция FExpand(FileName), получив имя файла FileName, расширяет его до полного имени, используя для этого имя текущего каталога. Если в качестве FileName задано имя с полным путем, функция не изменяет его. Если задано только имя файла, то дописывается текущий каталог. Если запись FileName начинается с символа «обратный слэш», то берется текущий диск и к нему дописывается имя FileName. Если запись FileName начинается с символов «..», то берется часть имени текущего каталога на уровень выше.

Процедура FSplit(WholeFileName, Dir, Name, Ext), получив в качестве аргумента полное имя файла WholeFileName, разделяет его на три составные части и возвращает переменные параметры Dir — каталог, Name — имя файла, Ext — расширение. Для каталога, имени файла и расширения в модуле DOS предусмотрены специальные типы — строки ограниченной длины: PathStr, NameStr, ExtStr.

Многие подпрограммы модуля Dos используют переменную DosError для указания на результат выполнения операции. Нулевое значение переменной указывает на отсутствие ошибок, ряд других возможных значений DosError приведен в таблице:

Код
2
3
5
8
18
Значение
Файл не найден
Путь не найден
Нет доступа
Недостаточно памяти
Больше нет файлов (при поиске)

Обратим внимание, что типизированные переменные пишутся в файл в том виде, в каком они используются в памяти ЭВМ. Если мы пытаемся прочитать содержимое такого файла обычными средствами DOS, например, нажав F3 в Norton Commander, или непосредственно в среде Паскаль, то каждый байт этих записей воспроизведется как соответствующий символ кодовой таблицы ASCII. Например, если файл имеет байтовый тип, и в него пишутся числа 65, 66, 67, то при его чтении мы увидим АВС. Такая запись данных компактна и удобна, если создаваемые файлы читаются другими программами, для которых эта кодировка естественна. В тех случаях, когда файлы предназначены для просмотра человеком, требуется перевод данных в текстовую форму.

Внешние устройства в качестве файлов

Связь с внешними устройствами в языке Паскаль осуществляется также через файловые переменные.

В Турбо Паскале существует два типа внешних устройств: устройства операционной системы и текстовые устройства.

Устройства операционной системы, с которыми осуществляется обмен информацией, могут быть описаны как файлы со стандартными именами. Эти имена следующие:

CON — консоль (клавиатура, дисплей). С этим устройством стандартно связаны файловые переменные Input и Output.

LPT1, LPT2, LPT3 — печатающие устройства. Если в системе один принтер, то он будет иметь имя LPT1. Если в программе используется стандартный модуль Printer (указан в разделе Uses), можно использовать для вывода на принтер стандартную файловую переменную Lst.

PRN — синоним LPT1.

COM1, COM2 — имена двух последовательных портов.

AUX — синоним COM1.

NUL — фиктивное внешнее устройство.

К текстовым устройствам относятся устройства, не поддерживаемые операционной системой или имеющие другие способы обращения. Например, устройство CRT, поддерживаемое стандартным модулем Сrt. Оно эквивалентно CON в операционной системе, но более быстродействующее и позволяет использовать разные цвета и окна.

С текстовым устройством нельзя связаться процедурой assign. Для связи с ним служит специальная модификация этой процедуры, например, для связи с устройством CRT следует использовать процедуру AssignCrt в модуле Crt.

Типизированные файлы в Паскаль

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

При описании типизированных файлов указывается тип его компонентов, число которых (длина файла) не фиксируется:

var имя_файла: file of тип_компонентов

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

var FileInt: file of Integer;

В этом описании указано, что элементами файла являются данные типа Integer , занимающие 2 байта (или 4). При этом отпадает необходимость в специальном разделении элементов файла, как это делалось в текстовых файлах. Также возможен произвольный доступ к элементам данных (этим типизированный файл несколько напоминает одномерный массив).

Чтобы можно было работать с типизированным файлом, необходимо, как и для текстовых файлов, сначала связать имя файловой переменной с внешним именем файла (оператор assign ). Затем нужно открыть его (используются операторы reset или rewrite ).

Операторы reset и rewrite открывают файл и для чтения, и для записи (а не только для чтения или только для записи, как при использовании текстовых файлов). Отличие их в том, что оператор reset открывает только существующий файл (если такого файла нет, будет сгенерирована ошибка времени выполнения). С другой стороны, оператор rewrite создает новый файл (если файл с таким именем уже имеется, то он будет уничтожен и создан заново).

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

Чтение из типизированного файла производится оператором read (но не readln ), а запись в него — оператором write (но не writeln ). Однако следует помнить, что в списке вывода оператора write могут быть только переменные. Типы элементов файла и типы переменных в списках ввода-вывода должны быть согласуемы по присваиванию. Элементами типизированных файлов могут быть числовые, символьные, булевы, строковые значения, массивы, записи, но не файлы или структуры с файловыми элементами.

Узнать количество элементов типизированного файла (размер файла) можно с помощью функции FileSize , для которой используется следующий синтаксис:

Например, если переменная k имеет тип LongInt , а f – файловая переменная типизированного файла, то выражение k := FileSize(f) , записывает в переменную k размер файла f .

Элементы типизированного файла нумеруются с нуля (порядковый номер последнего элемента файла на единицу меньше размера файла). Чтобы узнать, на каком элементе располагается указатель файла, используют функцию FilePos :

FilePos(имя_файла)

Текущим положением указателя можно управлять, для чего служит процедура Seek , которая использует следующий синтаксис:

Seek(имя_файла, номер_элемента)

Второй параметр (тип LongInt ) задает номер элемента (отсчет от 0), на который должен переместиться указатель файла. Рассмотрим несколько примеров.

Перейти к пятому (фактически шестому) элементу файла f :

Seek(f, 5);

Перейти к предыдущему элементу:

Seek(f, FilePos(f)-1);

Перейти в конец файла:

Seek(f, FileSize(f)-1);

Как и для текстовых файлов, можно использовать функцию Eof(имя_файла) , которая возвращает значение True , если текущий указатель расположен на признаке конца файла (то есть при выполнения равенства FilePos(имя_файла) = FileSize(имя_файла) ).

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

Текстовые файлы могут быть созданы текстовым редактором. Однако типизированные файлы создаются в результате работы какой-либо программы.

Пример записи данных в типизированный файл:

type t_subscriber = record surname: string[20]; tel: LongInt; end; var subscriber: t_subscriber; f: file of t_subscriber; i: Integer; begin Assign(f,'notebook.dat'); Rewrite(f); for i:=1 to 5 do begin with subscriber do begin Write('Surname: '); ReadLn(surname); Write('Phone: '); ReadLn(tel); end; Write(f, subscriber); end; Close(f); end.

Пример последовательного доступа к типизированному файлу:

type t_subscriber = record surname: string[20]; tel: LongInt; end; var subscriber: t_subscriber; f: file of t_subscriber; s: string[7]; begin Assign(f,'notebook.dat'); Reset(f); while not Eof(f) do begin Read(f, subscriber); with subscriber do begin str(tel,s); if Copy(s,1,2) = '33' then tel := tel+4000000; end; Seek(f,FilePos(f)-1); // возврат указателя назад Write(f,subscriber); end; Close(f); end. 

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

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

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