Files doc Гречкина П. В. Текстовый файл. Исключения Стр
Вид материала | Документы |
- Название доклада, 54.33kb.
- Г. Ч. Драконов (инициалы, фамилия автора, шрифт жирный), 85.62kb.
- Правила оформления печатных материалов Материалы конференции представляются в оргкомитет, 49.34kb.
- «3» дана информация о том, что называют малыми телами, их классификация, отсутствует, 5.83kb.
- Word. Задание "Редактирование текста", 14.24kb.
- Текстовые редакторы это программы для создания и редактирования текстовых документов, 263.8kb.
- Текстовый редактор. Работа с текстом Текстовый редактор (ТР), 62.2kb.
- Закон приморского края, 196.64kb.
- Лекция 11 doc V- 0,2, 710.33kb.
- Тема Ввод-вывод и файловая система. Файл 351111. doc, 294.63kb.
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 begin writeln(‘Ошибка при чтении значения для N’); writeln(‘Возможно введено не число?’); CloseFile(f); Readln; halt; // задержка и выход end; 4) Сразу же после окончания работы c файлом можно его закрыть CloseFile(f); …….. End. | 1) Объявить файловую переменную var f: TextFile; 2) Перед использованием 2а) Связать файловую переменную с файлом Begin …… AssignFile(f,’file.txt’); 2б) Открыть файл одним из способов в блоке try Try {попытаемся открыть} 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 then begin writeln('Ошибка открытия файла 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 then begin writeln('Ошибка создания файла 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]<0 then begin inc(m); B[m]:=i; end; {вывод результатов} if m<1 then 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]<0 then begin inc(m); B[m]:=i 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 нет'); 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);
Try
Try
{ввод исходных данных}
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);
Try
Try
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]<0 then begin inc(m); B[m]:=i end;
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;
Except
Writeln('Ошибка ввода из in_file.txt'); Readln; halt;
End;
Finally
CloseFile(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>