Files.doc Гречкина П.В. Текстовый файл. Исключения Стр. ФайлПри использовании файлов в программе (в качестве источников входных данных или для записи выходных данных) файл представляется в двух аспектах:- физическом; это именованная область памяти на внешнем носителе (диске), служащая для хранения данных; идентифицируется именем согласно правилам операционной системы (MS DOS, Windows и т.д.);- логическом; это представление файла в программе, зависящее от правил языка программирования; В Паскале файл в программе представляется файловой переменной, имя которой строится по обычным правилам Паскаля.Входной файл создается любым подходящим способом независимо от программы и до ее запуска. Выходной файл формируется программой. Связь логического и физического представленийСоответствие между физической и логической организацией устанавливается специальным оператором языка, связывающим физическое имя файла с файловой переменной; с этого момента программа имеет дело с файлом посредством этой файловой переменной, и термин «файл» применительно к операторам обработки файлов относится к файловой переменной (корректная формулировка звучала бы, например, так: «... чтение из файла, представленного файловой переменной f» вместо краткого: «чтение из файла f»). Этот оператор:AssignFile(,’’); Типы файловВ языке Паскаль существует три вида файлов: текстовые, типизированные, нетипизированные (бестиповые, двоичные). Чаще всего будем использовать текстовый файл. Структура файлаДля сравнения рассмотрим структуру типизированного и текстового файлов. Изобразим файл в виде полосы последовательно расположенных байтов. Любой файл заканчивается символом конца файла eof (первые буквы слов фразы «end of file»). Типизированный файл (следующий семестр)Все компоненты (минимальные считываемые или записываемые единицы) такого файла принадлежат к одному типу (и следовательно, имеют один размер); тип может быть любым статическим, кроме файлового: Компоненты размещены непосредственно один за другим. Файл хранится только на внешнем запоминающем устройстве (в частности, на диске).^ Описание файловой переменной: var :file of ;Значение файловой переменной – файл с компонентами заданного типа. Такие файлы мы будем изучать во втором семестре. Текстовый файлТекстовый файл – совокупность строк (последовательностей символов) переменной длины, заканчивающихся специальным символом eoln (конец строки; на клавиатуре набирается нажатием клавиши Enter): Описание файловой переменной: var : TextFile; или просто Text; Набранные на клавиатуре данные представляют собой стандартный входной файл. Содержимое дисплея при просмотре любого файла – стандартный выходной файл. Эти файлы используются при задании и просмотре данных. Для хранения данных последние записываются в файл на внешнем запоминающем устройстве (диске).В консольном приложении можно использовать стандартные файловые переменные – input (по умолчанию связан со стандартным входным текстовым файлом – клавиатурой) и output (по умолчанию связан со стандартным выходным текстовым файлом – дисплеем). Ввод/вывод можно перенаправить в другие текстовые файлы. Пример смотрите в файле TextFile.doc.^ Когда файлов несколько, или вы создаете неконсольное приложение, необходимо создавать собственную файловую переменную. Далее во всех задачах этого семестра будем использовать собственные файловые переменные и осуществлять ввод и вывод через нестандартные текстовые файлы. В них кириллица выводится корректно, т.к кодировки редактора кода и просмоторщика текстовых файлов Windows совпадают (по умолчанию).^ Описание собственной файловой переменной Здесь: ф.п. – файловая переменная, TextFile - стандартный тип (можно просто Text). Var : TextFile; ^ Специфика Компоненты-строки представлены во внешнем (символьном) виде: каждый байт являет собой код символа согласно таблице кодов.В программе из текстовых файлов вводятся и выводятся только неструктурированные данные – числа, символы, а также строки. Структурированные данные (массивы, записи) необходимо вводить по компонентам структуры (элементам, полям).Числа разделяются пробелами, табуляциями и/или символами конца строки – eoln.Символы считываются подряд (eoln – тоже символ!).Строки – про правила считывания строк – подробнее во втором семестре. Преимущества использования текстовых файлов перед остальными: - простота создания (непосредственный набор данных на клавиатуре); - наглядность (непосредственный просмотр средствами текстовых редакторов); - универсальность (можно обойтись только этим видом файлов). Недостатки – низкая скорость обработки, часто совмещенной с распознанием. – неравномерность размеров «порций»-строк и как следствие – только последовательный доступ – невозможность редактирования «на месте» (либо чтение, либо (до)запись, но не одновременно) Основные операторы для работы с текстовыми файлами: assignFile( ,’’) – связывает файловую переменную с файлом;rewrite( ) – создание и открытие нового файла для записи;reset ( ) – открытие существующего текстового файла (файла, связанного с файловой переменной ) для чтения;append( ) – открытие существующего текстового файла (файла, связанного с файловой переменной ) для дозаписи в конец;closeFile( ) – закрытие открытого файла. Операторы ввода-вывода:read( ,) – чтение данных; элемент списка ввода для текстового файла – число или символ или строка string; write( ,) - запись данных согласно списку вывода; элемент списка вывода для текстового файла – число или символ или строка string.readln( ,) - чтение данных согласно списку ввода и переход на следующую строку; если в строке данных остались данные, не вошедшие в список ввода, они игнорируютсяwriteln( ,) - запись данных в файл согласно списку вывода с добавлением в конце выведенной строки маркера конца строки (переход на следующую строку). Другие процедуры и функции, применимые для работы с текстовыми файлами:^ Eof Возвращает TRUE, если конец файла (символ конца файла (End-Of-File)), и FALSE в противном случае. eof(), например, eof(dat)SeekEof Возвращает TRUE, если до конца файла (до символа конца файла (End-Of-File)) остались только пробелы и символы конца строки, и FALSE в противном случае. SeekEof(), например, seekeof(dat)^ Eoln Возвращает TRUE, если конец строки (символ eoln (End-Of-Line)) в файле, и FALSE в противном случае. eoln(), например, eoln(dat)SeekEoln Возвращает TRUE, если до конца строки (до символа eoln (End-Of-Line)) в файле остались только пробелы, и FALSE в противном случае. seekeoln(), например, seekeoln(dat)^ Rename Переименовывает внешний файл. Rename(, ), например, Rename(dat, ‘new_file.txt’)Erase Удаляет внешний файл. Erase(), например, Erase(dat). Перед удалением файла убедитесь, что закрыли его.^ GetDir Возвращает имя текущей директории (папки) на заданном диске. GetDir(, ), например, GetDir(0, S). диск: 0 – текущий, 1 – A, 2 – B, 3 – C и т.д.^ ChDir Изменение текущей директории (папки). ChDir(), например, Chdir(‘D:\Tmp’)MkDir Создает поддиректорию (дочернюю папку). MkDir(),например, MkDir(‘D:\Tmp\New’) RmDir Удаляет пустую поддиректорию (дочернюю папку). RmDir(),например, RmDir(‘D:\Tmp\New’) IOResult Возвращает целое значение – код ошибки последней выполненной операции ввода/вывода, если отключить автоматическую проверку ошибок ввода/вывода (используя опцию компилятора {$I-}. Если IOResult вернула 0, последняя операция выполнена без ошибок. Альтернативный способ обработки ошибок – обработка исключительных ситуаций при включенной опции {$I+}. С проверкой ошибок (возвращают True/False) есть в модуле SysUtils функции: CreateDir(), DirectoryExists(), FileExists(), RemoveDir(), RenameFile(,), DeleteFile(). Итак, перед использованием файловой переменной, ее надо связать с внешним файлом с помощью процедуры AssignFile. Внешний файл – это обычно дисковый файл, но им может быть и устройство, такое как клавиатура или дисплей. Внешний файл хранит информацию, записанную в файл, или позволяет читать информацию из файла. После связывания с внешним файлом, файловая переменная должна быть «открыта» для ввода или вывода. Существующий файл может быть открыт для чтения с помощью Reset (только чтение) или Append (только запись в конец файла), а новый файл может быть создан и открыт только для записи с помощью процедуры Rewrite. Каждый файл – это линейная последовательность компонент. Текстовый файл является файлом последовательного доступа, т.е. прочитать/записать третью строку можно только прочитав/записав первые две строки. Например: Readln(dat); Readln(dat); Read(dat, a); или Writeln(res); Writeln(res); Write(res, a); После завершения работы с файлом его следует закрыть с помощью стандартной процедуры CloseFile. Файл будет обновлен, а файловую переменную можно связывать с другим внешним файлом. По умолчанию все обращения к стандартным процедурам ввода/вывода автоматически проверяются на предмет ошибки, и если ошибка возникает, возбуждается исключение (или программа завершается, если исключение не обработано). Эту автоматическую проверку можно включить или отключить, используя директивы компилятору {$I+} и {$I-}. При выключенной проверке исключение не возбуждается, и чтобы проверить результат операции ввода/вывода следует вызвать стандартную функцию IOResult. Этот вызов очистит флаг ошибки. Если его не сделать, то следующая операция ввода/вывода закончиться с ошибкой.^ Два способа безопасной работы с файлами. Использование директив компилятора для отключения автоматической реакции на ошибки при открытии файла. Использование механизма структурированной обработки исключений Более современный способ 1) Объявить файловую переменнуюvar f: TextFile; 2) Перед использованием 2а) Связать файловую переменную с файломBegin …… AssignFile(f,’file.txt’); 2б) Открыть файл одним из способов, отключив автоматическую реакцию на ошибки ввода/вывода{$I-} Reset(f); {$I+} // только для чтения {$I-} Rewrite(f); {$I+} { для перезаписи = создание + запись} {$I-} Append(f); {$I+} { для дозаписи в конец существующего текстового файла}2в) Тут же организовать свою проверку кода ошибки. Если IOResult=0, то ошибок нет, иначе можно, например, выдать сообщение и завершить программу. if IOResult 0 then begin writeln(‘Ошибка при открытии файла file.txt’); Readln; halt; // задержка и выход end;3) Если ошибки нет, можно работать с файломRead(f, ……); Readln(f, ……); Write(f, ……); Writeln(f, ……);Для каждого оператора (а не для целого блока операторов как при обработке исключений) опять же желательно проверить безошибочность его работы, например:{$I-} Readln(f, N); {$I+} if IOResult 0 then beginwriteln(‘Ошибка при чтении значения для N’);writeln(‘Возможно введено не число?’);CloseFile(f);Readln; halt; // задержка и выходend;4) Сразу же после окончания работы c файлом можно его закрытьCloseFile(f); …….. End. 1) Объявить файловую переменнуюvar f: TextFile; 2) Перед использованием 2а) Связать файловую переменную с файломBegin …… AssignFile(f,’file.txt’); 2б) Открыть файл одним из способов в блоке tryTry {попытаемся открыть} Reset(f); // только для чтения Rewrite(f); // для перезаписи = создание + записьAppend(f); { для дозаписи в конец существующего текстового файла}3) Тут же открыть блоки ^ Try, внутри которых можно работать с файломTry {чтобы закрыть в любом случае}Try {пытаемся прочитать/записать}Read(f, ……); Readln(f, ……); // для чтения из файлаWrite(f, ……); Writeln(f, ……); // для записи в файл4) В конце программы завершить все блоки ^ Try. Блок Finally выполняется в любом случае: и при возникновении ошибки, и при ее отсутствии; блок Except – только когда ошибка после Try.Except {при чтении/записи – третий Try}Writeln(‘Ошибка при работе с файлом file.txt’);^ Readln; halt;End;End;Finally {обязательно закрыть – второй Try}CloseFile(f);End;Except {при открытии файла – первый Try}On EInOutError do Begin Writeln(‘Ошибка при открытии файла file.txt’);Readln; halt;End;End;End.Блоки Try … Finally и Try … Except могут вкладывать друг в друга ЦЕЛИКОМ! Пример программы с обработкой ошибки открытия файлаЗадача. В заданном целочисленном одномерном массиве A из n элементов найти индексы всех отрицательных элементов (массив B из m элементов) Использование директив компилятора для отключения автоматической реакции на ошибки при открытии файла. Использование механизма структурированной обработки исключений. Результат заметен только при запуске exe-файла либо отключении автоматической остановки при возникновении исключительной ситуации! Program prov1;{$APPTYPE CONSOLE}var A: array [1..20] of real; B: array [1..20] of byte; n, m, i: byte; // 0..255 fin, fout: TextFile;Begin{ввод исходных данных}AssignFile(fin,'in_file.txt'); {$I-} Reset(fin); {$I+}if IOResult 0 thenbeginwriteln('Ошибка открытия файла in_file.txt');Readln; halt;end; Readln(fin); Readln(fin); //пропуск первых двух строк Readln(fin, n); {ввод n} Readln(fin); //пропуск четвертой строки for i:=1 to n do {ввод элементов массива A} read(fin, A[i]);CloseFile(fin);{вывод исходных данных}AssignFile(fout, 'out_file.txt'); {$I-} Rewrite(fout); {$I+}if IOResult 0 thenbeginwriteln('Ошибка создания файла out_file.txt');Readln; halt;end; Writeln(fout, 'Дан массив A из ', n,' элементов:'); for i:=1 to n do {вывод элементов массива A} write(fout, A[i]:4:1, ' '); writeln(fout);{решение} m:=0; for i:=1 to n do if A[i] begin inc(m); B[m]:=i; end;{вывод результатов} if m writeln(fout, 'Отрицательных элементов в массиве A нет') else begin writeln(fout, 'Результат - массив P:'); for i:=1 to m do {вывод элементов массива B} write(fout, B[i], ' '); writeln(fout); end;CloseFile(fout);end. Program prov2;{$APPTYPE CONSOLE}uses SysUtils; {нужен! там EInOutError}var A: array [1..20] of real; B: array [1..20] of byte; n, m, i: byte; // 0..255 fin,fout: TextFile;Begin AssignFile(fin,'in_file.txt'); Try Reset(fin);{ввод исходных данных} Readln(fin); Readln(fin); //пропуск строк readln(fin, n); {ввод n} Readln(fin); //пропуск строки for i:=1 to n do {ввод элементов массива A} read(fin, A[i]); CloseFile(fin);AssignFile(fout, 'out_file.txt'); Try Rewrite(fout);{вывод исходных данных} Writeln(fout, 'Дан массив A из ',n,' элементов:'); for i:=1 to n do write(fout, A[i]:4:1,' '); writeln(fout); m:=0; {решение задачи} for i:=1 to n do if A[i]if m>0 then {вывод результатов} begin writeln(fout, 'Результат - массив B:'); for i:=1 to m do write(fout, B[i], ' '); writeln(fout); end else writeln(fout, 'Отриц. элементов в массиве A нет'); CloseFile(fout); Except On EInOutError do Begin Writeln('Ошибка создания файла out_file.txt'); Readln; halt; End Else Begin Writeln('Другие ошибки… после послед. Try '); Readln; halt; End; End; Except Writeln('Ошибка открытия файла in_file.txt'); Writeln('Либо ввода (некорректные данные)');Readln; halt; End;end. Файл in_file.txt Файл out_file.txt создается программой Данные для задачиКоличество10Элементы5 -6 7 1 -2 8 4 -3 9 -5 Дан массив A из 10 элементов: 5.0 -6.0 7.0 1.0 -2.0 8.0 4.0 -3.0 9.0 -5.0Результат - массив B:2 5 8 10 С обработкой ошибок не только создания, но и чтения/записи:Program prov3;{$APPTYPE CONSOLE}uses SysUtils;var A: array [1..20] of real; B: array [1..20] of byte; n, m, i: byte; // 0..255 fin,fout: TextFile;Begin AssignFile(fin,'in_file.txt'); Try Reset(fin);TryTry{ввод исходных данных} Readln(fin); Readln(fin); //пропуск строк readln(fin, n); {ввод n} Readln(fin); //пропуск строки for i:=1 to n do {ввод элементов массива A} read(fin, A[i]);{вывод исходных данных}AssignFile(fout, 'out_file.txt'); Try Rewrite(fout);TryTry Writeln(fout, 'Дан массив A из ',n,' элементов:'); for i:=1 to n do write(fout, A[i]:4:1,' '); writeln(fout);Try m:=0; {решение задачи} for i:=1 to n do if A[i] Except Writeln(fout, 'Возникла ошибка в вычислениях при поиске решения'); End;if m>0 then {вывод результатов} begin writeln(fout, 'Результат - массив B:'); for i:=1 to m do write(fout, B[i], ' '); writeln(fout); end else writeln(fout, 'Отриц. элементов в массиве A нет');Except Writeln('Ошибка вывода в файл out_file.txt'); Readln; halt;^ End;Finally CloseFile(fout);End; Except Writeln('Ошибка открытия/создания файла out_file.txt'); Readln; halt; End;ExceptWriteln('Ошибка ввода из in_file.txt'); Readln; halt;End;FinallyCloseFile(fin);End; Except Writeln('Ошибка открытия файла in_file.txt'); Readln; halt; End;end.Методом обработки исключений можно пользоваться не только в сфере работы с файлами, но и при вычислении выражений. Например, деление на 0:Program prov4;{$APPTYPE CONSOLE}uses SysUtils; {нужен! там EDivByZero и EZeroDivide}var a: real; b, c: integer;^ Begin write('a='); readln(a); write('b='); readln(b); write('c='); readln(c);Try {попытаемся } writeln(a:5:2,' / ',b,' = ',(a/b):5:2); writeln(b,' / ',c,' = ', (b/c):5:2); writeln(c, ' div 0 =', c div (b-b));^ Except {возникли ошибки!} On EZeroDivide do Writeln('Вещественное число на ноль делить (/0) нельзя!'); On EDivByZero do Writeln('Целое число на ноль делить (div 0) нельзя!');Else Writeln('Другие ошибки');^ End;readln;End.Тесты № Смысл Исходные данные Ожидаемый результат 1 Ошибка при первом же делении a=2, b=0, c=2 Нельзя /0 2 Ошибка при втором делении a=2, b=1, c=0 2/1=2 и Нельзя /0 3 Ошибка только при последнем делении a=2, b=1, c=2 2/1=2 и 1/2=0.5 но Нельзя 2 div 0 Результат обработки исключений виден только при запуске exe-файла. При отладке приложения в среде Borland Delphi, обработкой исключений занимается сам Delphi. Он сообщает вам о возникающих исключениях, хотя эту автоостановку можно и отключить… (см. в конце) Поскольку выполнение блока операторов прерывается в месте возникновения ошибки, обрабатывать можно не целый блок сразу, а по отдельности: Program prov5;{$APPTYPE CONSOLE}uses SysUtils; {нужен! там EDivByZero и EZeroDivide}var a: real; b, c: integer;Begin write('a='); readln(a); write('b='); readln(b); write('c='); readln(c);Try writeln(a:5:2,' / 0 = ',(a/(b-b)):5:2); Except On EZeroDivide do Writeln('Вещественное число на ноль делить (/0) нельзя!'); Else Writeln('Ошибка в выражении!'); End;Try writeln(b,' / ',c,' = ', b/c:5:1); Except Writeln('Ошибка в выражении ', b,' / ',c,'!'); End;Try writeln(c, ' div 0 =', c div (b-b)); Except On EDivByZero do Writeln('Целое число на ноль делить (div 0) нельзя!'); Else Writeln('Ошибка в выражении!'); End;readln;end.Тесты № Смысл Исходные данные Ожидаемый результат 1 Ошибка при каждом делении a=2, b=0, c=2 Нельзя /0 Ошибка в выражении! Нельзя div 0 2 Ошибка при первом и третьем делении a=2, b=1, c=2 Нельзя /0 1 / 2 = 0.5 Нельзя div 0 Для отключения/включения автоостановки при возникновении исключительных ситуаций и появления извещения об имени исключения: в Delphi 2003-2007 зайдите в меню Tools Options, найдите слева в дереве пункт Debugger Exceptions CodeGear Debuggers ^ Language Exceptions, проверьте по рисунку соответствие флажков справа и одного снизу. Последний (в самом низу окна) говорит о том, надо ли информировать оператора об исключении окном диалога (см. ниже): при возникновении этого диалога надо ответить «Продолжить» (Continue), если ЕСТЬ СВОЯ обработка, либо «Прервать» (Break), если своего обработчика нет.в Delphi 7, используйте меню Tools Debugger Options и закладку Language Exceptions:0>0>1>0>