Files doc Гречкина П. В. Текстовый файл. Исключения Стр

Вид материалаДокументы

Содержание


Описание файловой переменной
Когда файлов
Описание собственной файловой переменной
 Специфика
Eof Возвращает TRUE, если конец файла (символ конца файла (End-Of-File)), и FALSE в противном случае. eof()
Eoln Возвращает TRUE, если конец строки (символ eoln (End-Of-Line)) в файле, и FALSE в противном случае. eoln()
Rename Переименовывает внешний файл. Rename(, )
GetDir Возвращает имя текущей директории (папки) на заданном диске. GetDir(, )
ChDir Изменение текущей директории (папки). ChDir()
Два способа безопасной работы с файлами.
Try, внутри которых можно работать с файломTry {чтобы закрыть в любом случае}
Try. Блок Finally
Readln; halt
End; Finally
Begin write('a='); readln(a); write('b='); readln(b); write('c='); readln(c); Try
Except {возникли ошибки!} On EZeroDivide
End;readln; End
Language Exceptions
Подобный материал:

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: