Назад Оглавление

Вперед

 

2.6. Файловый тип

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

<описание файлового типа>::= file of <тип компонент> 

     Если слово of и тип компонента опущены, то тип обозначает нетипизированный файл, который представляет собой канал ввода-вывода нижнего уровня. Нетипизированные файлы используются для прямого доступа к любому файлу на диске, независимо от его внутреннего формата. Для нетипизированных файлов в процедурах Reset и Rewrite допускается указывать дополнительный параметр, чтобы задать размер записи, использующийся при передаче файла. Обычно, принимаемая по умолчанию длина записи равна 128 байтам. Предпочтительной длиной записи является длина записи, равная 1, поскольку это единственное значение, которое позволяет точно отразить размер любого файла (когда длина записи равна 1, то в файле не могут присутствовать неполные записи, то есть записи с меньшей длиной). За исключением процедур Read и Write для всех нетипизированных файлов допускается использование любой стандартной процедуры, которые допускается использовать с типизированными файлами. Вместо процедур Read и Write здесь используются соответственно процедуры BlockRеаd и BlockWrite позволяющие пересылать данные с высокой скоростью. 

     Особым среди файловых типов является текстовый. При открытии текстового файла внешний файл интерпретируется специальным образом: считается, что он представляет собой последовательность символов, сгруппированных в строки, где каждая строка заканчивается символом конца строки (end-of-line), который представляет собой символ перевода каретки, за которым возможно следу╜ет символ перевода строки. Для текстовых файлов существует специальный вид операций чтения и записи (read и write), которые позволяют считывать и записывать значения, тип которых отличается от символьного типа Char. Такие значения автоматически переводятся в символьное представление и обратно. Например, Read(f, i), где i - переменная целого типа, приведет к считыванию последовательности цифр, интерпретации этой последовательности, как десятичного числа, и сохранению его в i. Имеются две стандартных переменных текстового типа - это Input и Оutput. Стандартная файловая переменная Input - это файл, доступный только для чтения, связанный со стандартным файлом ввода операционной системы (обычно это клавиатура), а стандартная файловая переменная Оutput √ это файл, доступный только для записи, связанный со стандартным файлом вывода операционной системы (обычно это дисплей). 

<описание текстового файла>::= text

    Типичный сценарий работы с файлом состоит из следующей последовательности действий:

1. связывание файловой переменной с именем дискового файла (функция Assign)

2. открытие файла в определенном режиме (Rewrite √ в режиме записи, Reset √ в режиме чтения, Append √ в режиме дополнения)

3. обработка элементов файла

4. закрытие файла (функция Close)

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

     Когда связь с внешним файлом установлена, для подготовки ее к операции ввода или вывода файловая переменная должна быть "открыта". Существующий файл можно открыть с помощью процедуры Reset, а новый файл можно создать и открыть с помощью процедуры Rewrite. Текстовые файлы, открытые с помощью процедуры Reset доступны только по чтению, а текстовые файлы, открытые с помощью процедуры Rewrite, доступны только по записи. Типизированные и нетипизированные файлы всегда допускают как чтение, так и запись, независимо от того были они открыты с помощью процедуры Reset или с помощью процедуры Rewrite. Альтернативным режимом открытия является режим дополнения. В этом режиме, при открытии существующего файла, указатель устанавливается не на первую запись (что характерно для Reset и Rewrite), а в конец файла и, таким образом, запись новых элементов осуществляется после существующих. Открытие в режиме дополнения выполняется операцией Append. 

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

var f: text; 

... 

while not eof(f) do read (f, element) 

... 

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

var f: file of Integer; 

... 

for i:= 0 to (FileSize(f) √ 1) do read (f, element) 

... 

     Обычно доступ к файлам организуется последовательно, то есть, когда элемент считывается с помощью стандартной процедуры Read или записывается с помощью стандартной процедуры Write, текущая позиция файла перемещается к следующему по порядку элементу файла. Однако к типизированным и нетипизированным файлам можно организовать прямой доступ с помощью стандартной процедуры Sееk, которая перемещает текущую позицию файла к заданному элементу. Для определения текущей позиции в файле можно использовать стандартную функцию FilePоs. 

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

     При работе с файлами типичным набором ошибок являются: открытие для чтения несуществующего файла, установка указателя на несуществующую запись, переполнение диска при создании файла или записи элементов в файл. Стандартная реакция системы на ошибки такого уровня приводит к аварийному завершению программы. Существует возможность избежать такого рода реакции исполняющей системы. Для этого существуют специальные директивы компилятора одна из которых - {$I-} √ выключает режим аварийного завершения при возникновении ошибок ввода/вывода, и обратная ей √ {$I+} √ включает. Этими директивами должен быть отмечен фрагмент кода, в котором используются функции работы с файлами. Тогда обработка ошибок, которые могут возникнуть при выполнении этих функций, должна выполняться в самом фрагменте кода, отмеченном директивами. Для этого используется стандартная функция IOResult, возвращающая код ошибки предыдущей файловой операции. Код является целым числом, причем его нулевое значение означает нормальное выполнение файловых операций. Следующий фрагмент кода использует функцию IOResult для проверки существования файла:

... 

{$I-} {отключение контроля ввода/вывода} 

reset(f) {попытка открыть файл} 

if IOResult = 0 then 

 begin 

  writeln (▒Файл существует▓); 

  close(f) 

 end 

 else writeln (▒Файл не доступен▓); 

{$I+} {отключение контроля ввода/вывода} 

... 

     Вызов функции IOResult также ╚очищает╩ ошибку которая могла произойти, поэтому если ее не вызвать, в текущем состоянии {$I+}, из-за оставшейся ошибки IOResult, следующая операция ввода-вывода завершится с ошибкой. 

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

Текст задания

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

Решение 

program formatting; 

const d= 60; {длина ╚новых╩ строк} 

var 

 BOOK, COPY: text; 

 c: char; 

 k: integer; 

begin 

 {перепись BOOK в COPY с удалением ╚концов строк╩} 

 assign( BOOK, 'c:\temp\Source.txt'); 

 assign( COPY, 'c:\temp\Copy.txt'); 

 reset( BOOK ); 

 rewrite( COPY ); 

 while not eof( BOOK ) do 

  if not eoln( BOOK ) then begin 

   read( BOOK, c ); 

   write( COPY, c ) 

  end 

 else read( BOOK, c ); 

 {перенос текста в BOOK с форматированием} 

 reset( COPY ); 

 rewrite( BOOK ); 

 k:= 0; {- порядковый номер литеры в строке} 

 while not eof( COPY ) do begin 

  read( COPY, c ); 

  write( BOOK, c ); 

  k:= k + 1; 

  if ( c= '.' ) or ( k= d ) then begin 

   writeln( BOOK ); 

    k:= 0 

  end 

 end 

end. 

Варианты заданий 

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

2. В 1-ом текстовом файле записана последовательность целых чисел, разделенных пробелами. Записать все положительные числа из этой последовательности во 2-ой текстовый файл. 

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

4. Имеется текстовый файл. Разбить его на строки так, чтобы каждая из них содержала не более 60 литер. 

5. В 1-ом текстовом файле записана последовательность целых чисел, разделенных пробелами. Записать все четные числа из этой последовательности во 2-ой текстовый файл. 

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

7. Текстовый файл разбит на строки и содержит более одной строки. Вывести число строк, начинающихся с буквы d. 

8. 1-ый непустой текстовый файл разбит на строки, длина которых не превосходит 80. Записать содержимое 1-ого файла во 2-ой, дополняя строки 1-ого файла символами "_" до 80. 

9. Текстовый файл разбит на строки и содержит более одной строки. Вывести число строк, оканчивающихся с буквой z. 

10. Текстовый файл разбит на строки и содержит более одной строки. Вывести число строк, которые начинаются и оканчиваются одной и той же литерой. 

11. Текстовый файл разбит на строки и содержит более одной строки. Вывести число строк, которые состоят из одинаковых литер. 

12. Текстовый файл разбит на строки и содержит более одной строки. Вывести число строк, имеющих четное количество литер. 

13. Текстовый файл разбит на строки и содержит более одной строки. Вывести число пустых строк. 

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

15. Имеется текстовый файл. Записать его содержимое в другой текстовый файл, формируя строки по 40 литер в каждой. 

16. Текстовый файл разбит на строки и содержит более одной строки. Записать его содержимое во второй текстовый файл, заменив все литеры f на 1. 

17. Текстовый файл разбит на строки и содержит более одной строки. Записать его содержимое во второй текстовый файл, заменив в четных строках литеры g на &. 

18. Текстовый файл разбит на строки и содержит более одной строки. Записать его содержимое во второй текстовый файл, заменив в нечетных строках литеры j на *. 

19. Имеется текстовый файл. Записать его содержимое в другой текстовый файл, формируя строки так, чтобы в каждой четной строке было 10 литер, в нечетной - 30. 

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

21. В 1-ом текстовом файле записана последовательность целых чисел, разделенных пробелами. Записать квадраты чисел этой последовательности во 2-ой текстовый файл. 

22. type exam= (math, geogr, phyz); student= record nfs: record name, fname, sname end; balls= array [exam] of 2..5; group: 101..116 end; course= file of student; Написать программу, которая оставляет в файле Course1 сведения только о тех студентах, которые успешно сдали все экзамены, и выводит сведения о студентах, имеющих хотя бы одну задолженность: выводит их фамилии и инициалы, номера групп и количество несданных экзаменов. 

23. Вывести картинку, изображающую умножение ╚столбиков╩ двух заданных натуральных чисел. 

24. Описать процедуру printlines( t ), выводящую построчно содержимое текстового файла t. 

type file1= file of char; Описать логическую функцию relation( f, v ), проверяющую, является ли содержимое файла f правильной записью ╚отношения╩, и если является, присваивающую логическому параметру v значение этого отношения. 

<отношение>::= <число> <знак отношения> <число> 

<знак отношения>::= < | = | > | <= | <> | >= 

<число>::= <цифра> | <цифры> 

<цифры>::= <неноль> <цифра> | <цифры> <цифра> 

<неноль>::= 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 

<цифра>::= 0 | <неноль> 

25. type FI= file of integer; Пусть в каждом из файлов f и g элементы упорядочены по неубыванию. Описать процедуру merge( f, g, h ), которая сливает эти файлы в один файл h, также упорядоченный по неубыванию. 

26. type FR= file of real; Описать функцию incr( f ) определяющую количество элементов в наиболее длинной возрастающей последовательности файла f. 

27. type FR= file of real; Описать логическую функцию mid( f, m ), которая определяет, имеет ли файл f типа FR нечетную длину, и, если имеет, присваивает параметру m средний элемент этого файла. 

28. Дана непустая последовательность слов, содержащих от 1 до 8 букв; между соседними словами √ запятая, за последним словом √ точка. Вывести все слова, отличные от последнего слова. 

29. Дана непустая последовательность слов, содержащих от 1 до 8 букв; между соседними словами √ запятая, за последним словом √ точка. Вывести все слова, наименьшей длины. 

30. type vec= file of 0..999; Описать логическую функцию issorted( r ), проверяющую, упорядоченны ли по возрастанию элементы непустого ряда r.

Назад Оглавление

Вперед