12.11.2. Примеры обработки ошибок ввода-вывода

We use cookies. Read the Privacy and Cookie Policy

Рассмотрим несколько практических примеров (везде далее f — файловая переменная).

- 263 -

1. Обработка отсутствия файла с данными. Если файл отсутствует, то действие процедуры открытия Reset вызовет ошибку (рис. 12.10 ).

| Assign( f, 'NoFile.TXT' );

| {$I-} { выключение проверки ввода-вывода }

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

| {$I+} { восстановление проверки }

| if IOResult<>0 { Если файл не может быть открыт, }

| then { то дать сообщение: }

| WriteLn( 'Файл не найден или не читается' )

| else begin { Иначе (код равен 0) все хорошо }

| Read( f, ... ); { и можно нормально работать с }

| ... { файлом f... }

| Close(f)

| end; {else и if}

Рис. 12.10

В случае неудачи при открытии файла к нему не надо применять процедуру закрытия Close.

По тому же принципу можно построить функцию анализа существования файла (рис. 12.11).

| FUNCTION FileExists( FileName : String ) : Boolean;

| VAR

| f : File; { тип файла не важен }

| BEGIN

| Assign( f, FileName ); { связывание файла f }

| {$I-} Reset( f ); {$I+} { открытие без контроля }

| if IOResult=0 { Если файл существует, }

| then begin { то его надо закрыть }

| Close{ f );

| FileExists := True end {then}

| else { иначе просто дать знать}

| FileExists := False;

| END;

Рис. 12.11

2. Выбор режима дозаписи в текстовый файл или его создания. Механизм остается тот же (рис. 12.12). Здесь f — текст-файловая переменная.

- 264 -

| Assign(f,'XFile.TXT'); {связывание файла f }

| {$I-} Append( f ); {$I+} {попытка открыть его для дозаписи}

| if IOResult<>0 {Если файл не может быть открыт, }

| then Rewrite( f ); {то создать его. }

| ...

| Write( f, ...); { нормальная работа с файлом }

| ...

| Close( f );

Рис. 12.12

3. Переход в заданный каталог или его создание, если переход возможен (рис. 12.13, S — строковая переменная).

| S := 'C:NEWDIR'; { задано имя каталога }

| {$I-} ChDir( S ); {$I+} { попытка перейти в него }

| if IOResult<>0 { Если не получается, }

| then begin

| MkDir( S ); {то сначала создать его, }

| ChDir( S ) { а уж потом перейти. }

| end; {if}

| { Подразумевается, что каталог S в принципе создаваем. }

Рис. 12.13

4. Построение «умных» ждущих процедур чтения данных с клавиатуры. Такие процедуры не будут реагировать на данные не своего формата (рис. 12.14).

| { Здесь используется ряд процедур из библиотеки }

| CRT; { модуля CRT. Они отмечены * в комментариях. }

{Процедура считывает с клавиатуры значение типа Integer, помещая его в переменную V. При этом игнорируется любой ввод, не соответствующий этому типу. X и Y — координаты текста запроса Comment. Проверка корректности значений X и Y не производится. }

PROCEDURE ReadInteger( X,Y : Byte; Comment : String;

| VAR V : Integer );

Рис. 12.14

- 265 -

| CONST

| zone =12; { ширина окна зоны ввода числа }

| VAR

| WN.WX : Word; {переменные для хранения размеров окна }

| BEGIN

| WN:=WindMin; WX:=WindMax; {Сохранение текущего окна }

| {$I-} { отключение режима проверки }

| GotoXY( X,Y ); {*перевод курсора в X,Y }

| Write( Comment ); { печать комментария ввода }

| Inc(X, Length(Comment)); { увеличение координаты X }

| Window( X,Y, X+zone,Y ); {*определение окна на экране }

| Repeat { Главный цикл ввода числа: }

| ClrScr; {* очистка окна ввода, }

| ReadLn( V ); { считывание значения при $I- }

| until (IOResult=0); { пока не введено целое }

| {$I+} { включение режима проверки }

| {*восстановление окна: }

| Window( Lo(WN)+1, Hi(WN)+1, Lo(WX)+1, Hi(WX)+1 )

| END; {proc}

| VAR i : Integer; { === ПРИМЕР ВЫЗОВА ПРОЦЕДУРЫ === }

| BEGIN

| ClrScr; {* очистка экрана }

| ReadInteger(10,10,'Введите целое число: ',i); { вызов }

| WriteLn; WriteLn( 'Введено i=', i ); { контроль }

| ReadLn { пауза до нажатия ввода}

| END.

Рис 12.14 (окончание)

В примере можно попутно устроить проверку диапазона значений V, переписав условие окончания цикла в виде

until (IOResult=0) and (V<Vmax) and (V>Vmin);

где Vmax и Vmin — границы воспринимаемых значений V. Аналогичным способом, меняя лишь типы переменной V, можно определить процедуры ReadByte, ReadWord, ReadReal и т.п. Справедливости ради надо отметить, что хотя описанная процедура ReadInteger спокойно относится к попыткам впихнуть в нее буквы, дроби и прочие неподходящие символы, она чувствительна к превышению диапазона значений типа Integer во входном числе и не обрабатывает его.

5. Работа с текстовыми файлами данных произвольного формата. Пусть существует файл из N столбцов цифр, содержащий в некоторых строках словесные комментарии вме-

- 266 -

сто числовых значений. На рис. 12.15 показано, как можно прочитать из файла все цифровые данные, игнорируя строки-комментарии, текстовые строки или строки пробелов (а так же пустые).

| CONST N=3; { пусть в файле данные даны в трех столбцах }

| VAR

| f : Text; { текст-файловая переменная }

| i : Byte; { счетчик }

| D : Array [1..N] of Real; { значения одной строки }

| { данных в формате Real }

| BEGIN

| Assign(f,'EXAMPLE.DAT'); { связывание файла f }

| Reset( f ); { открытие файла для чтения }

| {$I-} { отключение режима проверки }

| while not SeekEOF(f) do { Цикл до конца файла: }

| begin

| Read( f, D[1] ); { попытка считать 1-е число }

| if IOResult=0 { Если это удалось,то затем }

| then begin { читаются остальные числа: }

| for i:=2 to N do Read( f, D[i] );

| { и как-либо обрабатываются: }

| WriteLn( D[1]:9:2, D[2]:9:2, D[3]:9:2 )

| end; {if 10...}

| ReadLn( f ) { переход на следующую строку }

| end; {while} { конец основного цикла }

| {$I+} { включение режима проверки }

| Close( f ); { закрытие файла f }

| ReadLn { пауза до нажатия ввода }

| END.

Рис. 12.15

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

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