Методические указания к лабораторной работе “программирование алгоритмов обработки файловой информации” по дисциплине “Технология программирования”
1 Цель работы
Усвоение студентами приемов программирования работы с файлами и обработки файловой информации.
Краткие теоретические сведения
В Турбо Паскале различают текстовые файлы, типированные файлы и нетипированные файлы /3/.
При работе с файлами ключевым понятием является понятие переменной файлового типа или файловой переменной (ФП). В зависимости от класса файла ФП описывается одним из следующих способов:
- VAR<имя ФП>:Text - для текстового файла;
- VAR<имя ФП>:File of<Тип компонентов> - для типированного файла;
- VAR<имя ФП>:File - для нетипированного файла.
ФП связывается с именем файла оператором
ASSIGN(<ФП>’<путь к файлу>\<имя конкретного файла>’).
Этот оператор должен быть первым среди операторов, работающих с файлом. В кавычках указывается внешнее имя файла. Если во внешнем имени отсутствует указание пути, файл ищется в текущей директории.
Прежде чем станут доступны для чтения компоненты файла, его необходимо открыть оператором RESET(<ФП>), после чего автоматически текущим становится компонент с номером 0. Для чтения компонентов файла используются процедуры Readln и Read.
Текстовый файл не является однородной последовательностью символов, его компонентами являются строки, заканчивающиеся маркерами конца строки Eoln (занимает 2 байта и содержит коды : #13).
При работе с текстовым файлом список ввода (вывода) может содержать переменные символьного, строкового и любого числового типа. Запрещены в списке ввода (вывода) переменные-структуры (запись, массив, множество), но можно вводить из текстового файла простые значения полей записей или элементов массива.
Компоненты файла F1 могут иметь в программе следующее описание:
Var
FIO: String[20];
NGR: String[9];
X: String[1];
NPR, REZ: Word;
в описании фиксируется, “ФИО студента” занимает 20 позиций в записи, следующий за этим полем пробел и номер группы (NGR) занимают 9 позиций, затем следует один пробел (Х) и целочисленные поля номер предмета (NPR) и оценка (REZ).
Положим, что файл F1 имеет внешнее имя “Rezses.dat” и помещен в ту же директорию, что и файл программы, и приведём операторы доступа в программе к компонентам файла F1:
Var
f: text;
Begin
Assign(f, ‘Rezses.dat’);
Reset(f);
While not EOF(f) do
Begin
readln(f, FIO, NGR, X, NPR, REZ);
{операторы обработки данных из записи}
End;
Close (f)
End.
Отметим, что процедура Readln считывает строку от начала; всякий раз, как только все перечисленные в списке ввода переменные получат значения, остаток строки (если он есть) вместе с маркером конца строки пропускаются и программа готова читать следующую строку из файла для чтения. При вводе значения символьной переменной оператор Read считывает в неё очередной символ строки, в том числе и символы маркера конца строки или конца файла. При вводе значений числовой переменной символы считываются вплоть до пробела, символа табуляции, маркера конца строки или конца файла и интерпретируются, как одно значение.
Доступ к полям записи файла F1 можно было получить в программе и другим способом, описав запись F1, как строку символов (длина строки=20+1+8+1+1+1+1+2=35, где последним слагаемым являются 2 символа Eoln-маркера конца строки).
Type
Stro=String[35];
Var
fp: File of Stro;
NGR:String[8];
m, NPR, REZ:Word;
S:Stro;
Begin
Assign (fp, ‘Rezses.dat’);
Reset(fp);
Repeat
Read(fp, s);
NGR:=Copy (S,22,8);
Val (Copy (S, 31, 1), NPR, m);
if m<>0 then Writeln (‘нечисловой номер предмета’);
Val (Copy (S, 33, 1), REZ, m);
if m<>0 then Writeln(‘нечисловая оценка’);
{другие операторы обработки}
Until EOF (fp);
Close (fp)
End.
В языке СИ файлы рассматриваются как неструктурированные последовательности байтов, ввод-вывод которых осуществляется библиотечными функциями /9/. Библиотека языка СИ поддерживает несколько уровней ввода-вывода, из них для выполнения стандартных операций применяют ввод-вывод, ориентированный на поток. Функции библиотеки, поддерживающие такой обмен данными с файлами на уровне потока, позволяют обрабатывать данные разных размеров и форматов, обеспечивая при этом буферизированный ввод-вывод. Таким образом, согласно концепции языка СИ, поток - это файл вместе с предоставляемыми средствами буферизации.
Для того, чтобы можно было использовать функции библиотеки ввода-вывода, в программу необходимо включить заголовочный файл stdio.h, который содержит прототипы функций ввода-вывода, а также определения констант, типов и структур, требуемых для работы функций обмена с потоком.
Данные в файле становятся доступными после его открытия. При этом в исполняемой программе поток связывается со структурой предопределеннного типа FILE. Определение структурного типа FILE включено в заголовочный файл stdio.h и включает: указатель на буфер, указатель (индикатор) текущей позиции в потоке и другие аналогичные компоненты, поддерживающие обмен с потоком. При открытии потока в программу возвращается указатель на поток, который является адресом объекта структурированного типа FILE ( иначе говоря, совокупности всех тех компонент, о которых упоминалось выше). Этот указатель и будет определять поток во всех последующих операциях и должен быть объявлен в программе, например, следующим образом:
# include < stdio.h >
FILE *fp.
Объявленный указатель fp приобретет конкретное значение в результате выполнения функции открытия потока:
fp = fopen (имя_файла, режим_открытия).
Параметры имя_файла и режим_открытия являются строковыми данными, содержащими соответственно внешнее имя файла, связанного с потоком, и символьное обозначение режима открытия, например:
fp = fopen (t.txt, r),
где t.txt - внешнее имя файла данных в текущем каталоге; r обозначает режим работы с файлом (тип доступа к потоку).
Стандартно файл, связанный с потоком, можно открыть в одном из следующих режимов:
- r означает открытие для чтения существующего текстового файла;
- w открывает для записи новый текстовый файл, причем если файл с таким внешним именем уже существует на носителе, то его содержание будет потеряно;
-a открывает существующий текстовый файл для дозаписи (добавления новой порции) информации;
-r+ означает открытие существующего текстового файла как для чтения, так и для изменения содержимого файла;
- w+ открывает новый текстовый файл для чтения-записи и последующих многократных изменений содержимого файла, причем если файл уже существует, то предыдущее содержимое стирается;
-a+ открывает существующий текстовый файл для добавления или создает новый текстовый файл (если на носителе такого файла нет).
Обратите внимание, что во всех вышеперечисленных случаях поток открывается в текстовом режиме, для которого характерно, что прочитанная из потока комбинация символов CR (значение 13 - управляющий код ‘возврат каретки’) и LF (значение 10 - управляющий код ‘перевод строки’) преобразуется в один символ ‘\n’, имеющий значение, совпадающее с LF. При записи в поток в текстовом режиме осуществляется обратное преобразование ( т.е. символ ‘\n’ заменяется последовательностью CR LF). Если поток открыт для изменений, т.е. в параметре режима присутствует символ ‘+’, то разрешен как вывод в поток, так и чтение из него.
При открытии потока могут возникать такие характерные ошибки, когда на диске не найден файл, связанный с потоком, диск заполнен или защищен от записи. В таких случаях указатель на поток приобретает значение NULL, которое определено в файле stdio.h. Заметим, что значение указателя на поток в любом режиме, отличном от вышеуказанных ошибочных ситуаций, не бывает равным NULL. Поэтому типичная последовательность операторов при открытии текстового файла, связанного с потоком, и с проверкой ошибочных ситуаций может быть следующей:
if ((fp=fopen(t.txt, w))= = NULL)
{
perror (ошибка при открытии файла t.txt \n);
exit (0);
}
Для вывода на экран дисплея сообщения об ошибке при открытии потока используется стандартная библиотечная функция perror (), прототип которой находится в stdio.h.
После того, как файл открыт, конкретные значения полей записей файла можно либо считывать из него, либо записывать в файл (в зависимости от режима). Когда все операции с данными файла закончены, файл рекомендуется закрывать явно, для чего используется библиотечная функция fclose (указатель_на_поток). После закрытия файл может быть открыт повторно в другом режиме (этот прием часто используется, когда в одной программе создается новый файл, а затем информация из него обрабатывается согласно некоторому алгоритму).
Следует обратить внимание, что понятие текстового файла в языках программирования Паскаль и СИ не эквивалентны, единственным общим свойством является то, что в обоих языках в текстовых файлах записи отделяются друг от друга комбинацией кодов ‘возврат каретки’ и ‘перевод строки’. Понятию текстового файла Паскаля как совокупности записей из полей данных символьного типа в языке СИ соответствует текстовый файл форматного ввода-вывода (такой же файл создается стандартным текстовым редактором EDIT MS DOS, достоинством файлов такого типа является то, что конкретные значения полей записей из них могут непосредственно отображаться на экран дисплея без преобразования вьюером VIEW). Логичнее было бы во всех языках программирования и системах программирования такие файлы называть символьными, что могло бы исключить разночтение.
В языке программирования СИ ввод-вывод таких файлов выполняется функциями fscanf () и fprintf(), которые имеют следующие прототипы:
int fscanf (указатель_на_поток, форматная_строка, список_адресов_переменных);
int fprintf (указатель_на_поток, форматная_строка, список_адресов_переменных).
Эти функции очень схожи с функциями scanf () и printf() для форматного обмена с клавиатурой и дисплеем, отличие лишь в том, что в случае обмена, ориентированного на поток, в качестве первого параметра функций требуется задавать указатель на поток, с которым производится обмен.
Для полноты изложения приведем фрагмент программы на языке СИ, включающий операторы чтения результатов сессии из вышеприведенного файла Rezses.dat:
# include < stdio.h >
void main()
{
char fio[21], ngr[9];
int npr,rez;
FILE *f;
if ((f=fopen(Rezses.dat, r))= = NULL)
{
perror (ошибка при открытии файла Rezses.dat \n);
exit (0);
}
while ( fscanf(f, %s%s%d%d, fio, ngr, &npr,&rez)!=EOF);
{ операторы обработки данных из записи}
fclose(f);
}
Достарыңызбен бөлісу: |