Обработка ошибок ввода вывода паскаль



العربية (ar)




English (en)

español (es)

suomi (fi)
français (fr)



日本語 (ja)






русский (ru)






中文(中国大陆)‎ (zh_CN)
中文(台灣)‎ (zh_TW)

Введение

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

Процедурный стиль

Это довольно старый стиль, использующейся ещё во времена, когда Pascal не был объектно-ориентированным языком. Суть его в том, что задается тип файла, определяющий, какие будут храниться в нем данные. Для этого, используется конструкция вида: file of <тип данных>, где <тип данных> — название типа, который хранит в себе файл. Помимо стандартных типов (integer, extended, char и т.д.), существует особый тип — TextFile. Он определят, что каждая строка заканчивается специальным(ми) символом(ами) конца строки (См. LineEnding). Эти файлы могут быть открыты и отредактированы внутри среды Lazarus или в любом другом текстовом редакторе.

Ниже представлены примеры создания собственных типов файлов:

...
type
  TIntegerFile  = file of integer;  // Позволяет писать только целые числа в файл
  TExtendedFile = file of extended; // Позволяет писать только дробные цифры в файл
  TCharFile     = file of char;     // Позволяет писать только одиночные символы в файл

Обработка ошибок ввода/вывода

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

Это задаётся с помощью специальной директивы компилятора:

{$I+} // В случаи ошибки будет вызвано исключение EInOutError (по умолчанию)
{$I-} // Подавлять ошибки ввода-вывода: проверьте переменную IOResult для получения кода ошибки.

В случаи подавления ошибок ввода-вывода ({$I-}) результат операции с файлом будет храниться в переменной IOResult типа cardinal (числовой тип). Каждое число, хранимое в IOResult определяет тип возникшей ошибки(подробнее: [1]).

Процедуры работы с файлами

Эти процедуры и функции находятся в модуле system. Для более подробной информации смотрите документацию FPC:

ссылка на модуль 'System'.
  • AssignFile (не допускайте использование процедуры Assign) — Связывает переменную с файлом
  • Append — Открывает существующий файл для записи данных в конец и их редактирования
  • BlockRead — Чтение данных из не типизированного файла в память
  • BlockWrite — Запись данных из памяти в не типизированный файл
  • CloseFile (не допускайте использование процедуры Close) — Закрыть открытый файл
  • EOF — Проверка наличия конца файла
  • Erase — Стереть файл с диска
  • FilePos — Получить позицию в файле
  • FileSize — Получить размер файла
  • Flush — Записать файловый буфер на диск
  • IOResult — Возвращает результат последней операции вводавывода
  • Read — Считать из текстового файла
  • ReadLn — Считать из текстового файла и перейти к следующей строке
  • Reset — Открыть файл для чтения
  • Rewrite — Создать и открыть файл для записи
  • Seek — Изменить позицию в файле
  • SeekEOF — Переместить позицию в файле в его конец
  • SeekEOLn — Переместить позицию в файле в конец строки
  • Truncate — Удалить все данные, после текущей позиции
  • Write — Записать переменную в файл
  • WriteLn — Записать переменную в текстовый файл и перейти к новой строке

Пример

Пример работы с текстовым файлом (тип TextFile):

program CreateFile;

uses
 Sysutils;

const
  C_FNAME = 'textfile.txt';

var
  tfOut: TextFile;

begin
  // Связываем имя файла с переменной
  AssignFile(tfOut, C_FNAME);

  // Использовать исключение для перехвата ошибок (это по умолчанию и указывать не обязательно)
  {$I+}

  // Для обработки исключений, используем блок try/except
  try
    // Создать файл, записать текст и закрыть его.
    rewrite(tfOut);

    writeln(tfOut, 'Пример текстового файла!');
    writeln(tfOut, 'Пример записи числа: ', 42);

    CloseFile(tfOut);

  except
    // Если ошибка - отобразить её
    on E: EInOutError do
      writeln('Ошибка обработки файла. Детали: ', E.ClassName, '/', E.Message);
  end;

  // Выводим результат операции и ожидаем нажатие Enter
  writeln('Файл ', C_FNAME, ' создан. Нажмите ВВОД для выхода.');
  readln;
end.

Теперь откройте файл в любом текстовом редакторе и вы увидите, что пример текста, записан в нем!
Вы можете проверить работу обработки ошибок, установив атрибут файла «только для чтения» и снова запустив программу.

Обратите внимание, что в примере используется блок try/except. Данный способ позволяет выполнять несколько операций с файлами и использовать обработку исключений.
Вы также можете использовать режим {$I-}, но тогда вам придется проверять переменную IOResult после каждой операции с файлами для контроля ошибок.

Ниже приведен пример записи текста в конец файла:

program AppendToFile;

uses
 Sysutils;

const
  C_FNAME = 'textfile.txt';

var
  tfOut: TextFile;

begin
  // Связываем имя файла с переменной
  AssignFile(tfOut, C_FNAME);

  // Для обработки исключений, используем блок try/except
  try
    // Открыть файл для записи в конец, записать текст и закрыть его.
    append(tfOut);

    writeln(tfOut, 'Ещё пример текстового файла!');
    writeln(tfOut, 'Результат 6 * 7 = ', 6 * 7);

    CloseFile(tfOut);

  except
    on E: EInOutError do
     writeln('Ошибка обработки файла. Детали: ', E.Message);
  end;

  // Выводим результат операции и ожидаем нажатие Enter
  writeln('Файл ', C_FNAME, ' возможно содержит больше текста. Нажмите ВВОД для выхода.');
  readln;
end.

Чтение текстового файла:

program ReadFile;

uses
 Sysutils;

const
  C_FNAME = 'textfile.txt';

var
  tfIn: TextFile;
  s: string;

begin
  // Вывод некой информации
  writeln('Чтение содержимого файла: ', C_FNAME);
  writeln('=========================================');

  // Связываем имя файла с переменной
  AssignFile(tfIn, C_FNAME);

  // Для обработки исключений, используем блок try/except
  try
    // Открыть файл для чтения
    reset(tfIn);

    // Считываем строки, пока не закончится файл
    while not eof(tfIn) do
    begin
      readln(tfIn, s);
      writeln(s);
    end;

    // Готово. Закрываем файл.
    CloseFile(tfIn);

  except
    on E: EInOutError do
     writeln('Ошибка обработки файла. Детали: ', E.Message);
  end;

  // Выводим результат операции и ожидаем нажатие Enter
  writeln('=========================================');
  writeln('Файл ', C_FNAME, ' считан. Нажмите ВВОД для выхода.');
  readln;
end.

Объектный стиль

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

Кроме того, большинство классов обработки строк, могут иметь возможность загружать/сохранять содержимое из/в файл. Эти методы обычно называются SaveToFile и LoadFromFile.

Двоичные файлы

Для прямого доступа к файлам, так же удобно использовать класс TFileStream. Этот класс представляет собой инкапсуляцию системных процедур FileOpen, FileCreate, FileRead, FileWrite, FileSeek и FileClose, расположенных в модуле SysUtils.

Процедуры ввода-вывода

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

program WriteBinaryData;
{$mode objfpc}

uses
  Classes, Sysutils;

const
  C_FNAME = 'binarydata.bin';

var
  fsOut    : TFileStream;
  ChrBuffer: array[0..2] of char;

begin
  // Создать некоторые случайные данные, которые будут храниться в файле
  ChrBuffer[0] := 'A';
  ChrBuffer[1] := 'B';
  ChrBuffer[2] := 'C';

  // Перехват ошибок в случае, если файл не может быть создан
  try
    // Создать экземпляр потока файла, записать в него данные и уничтожить его, чтобы предотвратить утечки памяти
    fsOut := TFileStream.Create( C_FNAME, fmCreate);
    fsOut.Write(ChrBuffer, sizeof(ChrBuffer));
    fsOut.Free;


  // Обработка ошибки
  except
    on E:Exception do
      writeln('Файл ', C_FNAME, ' не создан, так как: ', E.Message);
  end;

  // Выводим результат операции
  writeln('Файл ', C_FNAME, ' создан. Нажмите ВВОД для выхода.');
  //Ожидаем нажатие Enter
  readln;
end.

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

program ReadBinaryDataInMemoryForAppend;
{$mode objfpc}

uses
  Classes, Sysutils;

const
  C_FNAME = 'binarydata.bin';

var
  msApp: TMemoryStream;

begin
  // Создаем поток в памяти
  msApp := TMemoryStream.Create;

  // Перехват ошибок в случае их возникновения
  try
    // Считать данные в память
    msApp.LoadFromFile(C_FNAME);

    // Переходим в конец данных
    msApp.Seek(0, soEnd);

    // Запись неких данных в поток
    msApp.WriteByte(68);
    msApp.WriteAnsiString('Некий текст');
    msApp.WriteDWord(671202);

    // Запись данных на диск (файл будет перезаписан)
    msApp.SaveToFile(C_FNAME);

  // Обработка ошибки
  except
    on E:Exception do
      writeln('Файл ', C_FNAME, ' не удалось считать или записать, так как: ', E.Message);
  end;

  // Освобождаем память и уничтожаем объект
  msApp.Free;

  // Выводим результат операции и ожидаем нажатие Enter
  writeln('Файл ', C_FNAME, ' дописан. Нажмите ВВОД для выхода.');
  readln;
end.

Для работы с файлами большого объёма, рекомендуется использовать буфер, например в 4096 байт.

var
  TotalBytesRead, BytesRead : Int64;
  Buffer : array [0..4095] of byte;  // или, array [0..4095] of char
  FileStream : TFileStream;

try
  FileStream := TFileStream.Create;
  FileStream.Position := 0;  // Установим позицию в начало файла
  while TotalBytesRead <= FileStream.Size do  // Пока объем считанных данных меньше размера файла
  begin
    BytesRead := FileStream.Read(Buffer,sizeof(Buffer));  // Считать 4096 байт данных
    inc(TotalBytesRead, BytesRead);                       // Увеличиваем TotalByteRead на размер буфера, т.е. 4096 байт
    // Что-то делаем с буфером данных
  end;

Копирование файла

Теперь,зная методы работы с файлами, мы можем реализовать простую функцию копирования файла, скажем FileCopy.(такой функции нет в FreePascal, хотя Lazarus её имеет copyfile):

program FileCopyDemo;
// Пример функции FileCopy

{$mode objfpc}

uses
  classes;

const
  fSource = 'test.txt';
  fTarget = 'test.bak';

function FileCopy(Source, Target: string): boolean;
// Копируем файл с путем в Source в файл с путем Target.
// Кэшируем весь файл в память.
// В случаи успеха возвращаем true, в случаи ошибки - false.
var
  MemBuffer: TMemoryStream;
begin
  result := false;
  MemBuffer := TMemoryStream.Create;
  try
    MemBuffer.LoadFromFile(Source);
    MemBuffer.SaveToFile(Target); 
    result := true
  except
    //Подавляем исключение; результатом функции является значение false по умолчанию
  end;
  // Очистка
  MemBuffer.Free
end;

// Пример использования
begin
  If FileCopy(fSource, fTarget)
    then writeln('Файл ', fSource, ' скопирован в ', ftarget)
    else writeln('Файл ', fSource, ' не скопирован в ', ftarget);
  readln()
end.

Обработка текстовых файлов (TStringList)

Для текстовых файлов можно использовать класс TStringList, чтобы загрузить весь файл в память и иметь легкий доступ к его строкам. Вы также можете записать StringList обратно в файл:

program StringListDemo;
{$mode objfpc}

uses
  Classes, SysUtils;

const
  C_FNAME = 'textfile.txt';

var
  slInfo: TStringList;

begin
  // Создаем TStringList для обработки текстового файла
  slInfo := TStringList.Create;

  // Для обработки исключений, используем блок try/except
  try
    // Загружаем файл в память
    slInfo.LoadFromFile(C_FNAME);

    // Добавляем некие строки
    slInfo.Add('Некая строка');
    slInfo.Add('Ещё одна строка.');
    slInfo.Add('Всё, хватит.');
    slInfo.Add('Сейчас ' + DateTimeToStr(now));

    // Записать содержимое на диск, заменив исходное содержимое
    slInfo.SaveToFile(C_FNAME);

  except
    // Обработка ошибки
    on E: EInOutError do
      writeln('Произошла ошибка обработки файла. Причина: ', E.Message);
  end;

  // Очистка
  slInfo.Free;

  // Выводим результат операции и ожидаем нажатие Enter
  writeln('Файл ', C_FNAME, ' обновлен. Нажмите ВВОД для выхода.');
  readln;
end.

Демо: сохранить одну строку в файл

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

program SaveStringToPathDemo;
{$mode objfpc}

uses
  Classes, sysutils;

const
  C_FNAME = 'textstringtofile.txt';

// SaveStringToFile: функция для хранения строк текста в файле на диске.
//   Если результат функции равен True, то строка была написана
//   Иначе произошла ошибка
function SaveStringToFile(theString, filePath: AnsiString): boolean;
var
  fsOut: TFileStream;
begin
  // По умолчанию результат неудачный
  result := false;

  // Записать данную строку в файл, перехватывая ошибки в процессе записи.
  try
    fsOut := TFileStream.Create(filePath, fmCreate);
    fsOut.Write(theString[1], length(theString));
    fsOut.Free;

    // На данном этапе известно, что запись прошла успешно.
    result := true

  except
    on E:Exception do
      writeln('Строка не записана. Детали: ', E.ClassName, ': ', E.Message);
  end
end;

//
// Основная программа
//
begin
  // Пытаемся сохранить текст в файл и выводим результат операции
  if SaveStringToFile('>> этот текст сохраняется <<', C_FNAME) then
    writeln('Текст успешно записан в файл.')
  else
    writeln('Не удалось сохранить текст в файл.');

  // Ждем нажатия Enter
  readln
end.

Смотрите так же

  • CopyFile — функция Lazarus, которая копирует файл
  • File

Дополнительные функции работы с файлами

Модуль
System

ChDir

Выполняет
смену текущего каталога

MkDir

Создает
подкаталог

RmDir

Удаляет
подкаталог (пустой)

GetDir

Получить
текущий каталог на заданном диске

Модуль
DOS

DiskFree

Число
свободных байтов на диске

DiskSize

Размер
диска в байтах

GetFAttr

Получение
атрибутов неоткрытого файла

SetFAttr

Задание
атрибутов неоткрытого файла

FSplit

Получение
составных частей имени файла

FExpand

Формирование
полного имени файла

FSearch

Поиск
файла в списке католога

FindFirst

Поиск
в указанном или текущем каталоге
первого файла, соответствующего
заданному шаблону и атрибутам

FindNext

Поиск
следующего файла, соответствующего
шаблону и атрибутам, заданным в
последнем обращении к FindFirst

Прототипы
процедур FindFirst
и FindNext
имеют вид:

FindFirst(Path:
String; Attrib: Word; Var SR: SearchRec);

FindNext(Var
SR:
SearchRec);

Для
работы с этими подпрограммами требуются
следующие предопределенные описания:

  1. Константы

Const

ReadOnly
= $01; только
для чтения

Hidden = $02; скрытый

SysFile =
$04; системный (непереносимый)

Volume ID = $08; метка
диска

Directory =
$10; подкаталог

Archive = $20; архивный

AnyFile = $3F; сумма
всех предыдущих

Эти атрибуты можно
складывать или вычитать (из anyfile).

  1. Переменная
    DOSError.
    Она используется для анализа ошибок
    MS
    DOS.
    Значение этой переменной, равное нулю,
    соответствует отсутствию ошибки. Смысл
    некоторых ненулевых кодов следующий:

2
– файл не найден

3
– маршрут не найден

5
– доступ к файлу запрещен

6
– неправильная обработка

8
– недостаточно памяти

10
– неверные установки значений параметров
среды

11
– неправильный формат

18
– файлов нет

При
работе процедуры FindFirst
возможны ошибки с номерами 2 и 18, а при
работе FindNext
– только 18.

3)
Тип

Type

SearchRec
= record

Fill: array[1..21] of byte; {системное поле}

attr: byte; {байт атрибутов}

time: longint; {время
создания}

size: longint; {размер
файла}

name: string[12]; {имя файла}

end;

Поля
переменной этого типа содержат информацию
о последнем файле, найденном с помощью
FindFirst
и FindNext.

Процедура
FindFirst
при заданных имени файла и атрибутах
должна вызываться лишь один раз. Она
записывает в поля переданной ей переменной
SR
типа SearchRec
информацию о первом найденном файле,
удовлетворяющем заданным условиям. Эта
информация в дальнейшем будет
использоваться процедурой FindNext,
которая всегда вызывается после FindFirst
и заполняет поля переменной SR
информацией о следующем найденном
файле.

Контроль
работы этих процедур ведется с помощью
переменной DOSError:
если файла нет, то DOSError<>0.

Обработка ошибок ввода-вывода

Все рассмотренные
ранее программы были написаны так, что
возможные ошибки ввода-вывода
игнорировались. Однако реально это не
так. В ТР стандартной реакцией на наличие
ошибок в вашей программе является
следующее: ваша программа аварийно
завершается и выдает сообщение:

Runtime
error
<номер> <смещение>.

Такое сообщение
буде полезно вам как программистам при
поиске места и причины ошибки в программе.
Однако показывать такое сообщение
пользователю вашей программы будет не
совсем дружественно.

Для того, чтобы
ваша программа из-за ошибки аварийно
не завершалась и для того, чтобы не
пугать пользователей непонятными им
сообщениями, вам необходимо перехватить
инициативу по обработке ошибок у системы
и писать собственные обработчики ошибок
стадии выполнения (исключений). Традиционно
обработка ошибок в программах
осуществляется с помощью установки
флагов

случае ошибки) и последующего анализа
этих флагов. Для перехвата ошибок
ввода-вывода на Паскале необходимо:

  1. Специальным
    образом оформить каждый фрагмент
    программы, которые потенциально могут
    вызвать ошибку. К таким фрагментам
    относятся — открытие файда, чтение из
    файла, запись в файл.

  2. При наличии такого
    специального оформления необходимо
    по завершению фрагмента проверить:
    была ошибка или нет. Если была, то вы
    должны выполнить ее обработку (хотя бы
    вывести свое сообщение).

Пример:

reset(f);

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

Специальное
оформление потенциально опасных участков
программы состоит в том, что
вы должны
как бы завернуть каждый опасный участок
в специальный код: выше
и ниже опасного фрагмента программы

вы должны
расположить две директивы компилятора:

{$I-}
— указывает на то, что необходимо
отключить системный контроль ошибок

reset(f);

{$I+}
— указывает на то, что необходимо включить
системный контроль ошибок

При наличии
директивы компилятора {$I-}
даже при наличии ошибок в/в программа
аварийно не завершается и ход выполнения
программы не нарушается.

Замечание:
По умолчанию действует директива {$i+}.

Контроль ошибок
в/в производится с помощью функции
IOResult
. Если ошибка имеет место, то значение
этой функции отлично от нуля. Поэтому
типичный шаблон обработки ошибки
ввода-вывода имеет вид:

If
IOResult
<> 0 Then
{обработка ошибки};

Обычно обработка
ошибки сводится к сообщению об ошибки
и завершению вашей программы (с помощью
процедуры HALT
или EXIT).

Замечание:
Опросить функцию IOResult
можно лишь
один раз

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

Пример.

{$I-}

reset(f);

{$I+}

If
IOResult <> 0

then
begin

Writeln(‘Ошибка
открытия
файла’);

Halt;

end;

Соседние файлы в папке WORD

  • #

    15.04.2015439.06 Кб306.docx

  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #
  • #

Компилятор Турбо Паскаля позволяет генерировать выполнимый код в двух режимах: с проверкой корректности ввода-вывода и без нее. В среде программирования этот режим включается в меню

— 262 —

Options/Compiler/IO-checking. При включении в программу ключ режима компиляции обозначается как

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

{$I-} — режим отключен.

По умолчанию, как правило, действует режим $I+. Этот ключ компиляции имеет локальную сферу влияния. Можно многократно включать и выключать режим, вставляя в текст программы конструкции {$I+} и {SI-}, тем самым создавая области с контролем ввода-вывода и без него.

При включенном режиме проверки любая ошибка ввода-вывода будет фатальной: программа прервется, выдав номер ошибки. Возможные номера ошибок ввода-вывода находятся в диапазоне от 2 до 200 ( от 2 до 99 — это коды ошибок DOS, от 100 до 149 — ошибки, диагностируемые самой программой, и от 150 до 200 — критические аппаратные ошибки). Расшифровка кодов ошибок с краткими комментариями приведена в табл. 12.6 в конце этого раздела.

Если отключить режим проверки, то при возникновении ошибки ввода-вывода программа уже не будет прерываться, а продолжит работу со следующего оператора. Результат операции ввода-вывода, вызвавшей ошибку, будет неопределен. При этом код ошибки будет сохранен в предопределенной системной переменной InOutRes. Однако для опроса этого кода лучше пользоваться специальной функцией Турбо Паскаля.

7.4 Обработка текстовых файлов в языке Free Pascal

При работе с текстовыми файлами следует учесть следующее:

  1. Действие процедур reset, rewrite, close, rename, erase и функции eof аналогично их действию при работе с компонентными (типизированными) файлами.
  2. Процедуры seek, trunсate и функция filepos не работают с текстовыми файлами.
  3. Можно пользоваться процедурой открытия текстового файла append(f), где f — имя файловой переменной. Эта процедура служит для открытия файла в режиме дозаписи в конец файла. Она применима только к уже физически существующим файлам, открывает и готовит их для добавления информации в конец файла.
  4. Запись и чтение в текстовый файл осуществляются с помощью процедур write, writeln, read, readln следующей структуры:

read ( f, x1, x2, x3,…, xn );

read ( f, x );

readln ( f, x1, x2, x3,…, xn );

readln ( f, x );

write ( f, x1, x2, x3,…, xn );

write ( f, x );

writeln ( f, x1, x2, x3,…, xn );

writeln ( f, x );

В этих операторах f — файловая переменная. В операторах чтения (read, readln) x, x1, x2, x3,…, xn — переменные, в которые происходит чтение из файла. В операторах записи write, writeln x, x1, x2, x3,…, xn — переменные или константы, информация из которых записывается в файл.

Есть ряд особенностей при работе операторов write, writeln, read, readln с текстовыми файлами. Имена переменных могут быть целого, вещественного, символьного и строкового типа. Перед записью данных в текстовый файл с помощью процедуры write происходит их преобразование в тип string. Действие оператора writeln отличается тем, что после указанных переменных и констант в файл записывается символ «конец строки».

При чтении данных из текстового файла с помощью процедур read, readln происходит преобразование из строкового типа к нужному типу данных. Если преобразование невозможно, то генерируется код ошибки, значение которого можно узнать, обратившись к функции IOResult. Компилятор Free Pascal позволяет генерировать код программы в двух режимах: с проверкой корректности ввода-вывода и без неё.

В программу может быть включен ключ режима компиляции. Кроме того, предусмотрен перевод контроля ошибок ввода-вывода из одного состояния в другое:

  • {$I+} — режим проверки ошибок ввода-вывода включён;
  • {$I-} — режим проверки ошибок ввода-вывода отключён.

По умолчанию, как правило, действует режим {$I+}. Можно многократно включать и выключать режимы, создавая области с контролем ввода и без него. Все ключи компиляции описаны в приложении.

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

Если убрать режим проверки, то при возникновении ошибки ввода-вывода программа не будет останавливаться, а продолжит работу со следующего оператора. Результат операции ввода-вывода будет неопределён.

Для опроса кода ошибки лучше пользоваться специальной функцией IOResult, но необходимо помнить, что опросить её можно только один раз после каждой операции ввода или вывода: она обнуляет своё значение при каждом вызове. IOResult возвращает целое число, соответствующее коду последней ошибки ввода-вывода. Если IOResult=0, то при вводе-выводе ошибок не было, иначе IOResult возвращает код ошибки. Некоторые коды ошибок приведены в табл. 7.9.

Таблица
7.9.
Коды ошибок операций ввода-вывода

Код ошибки Описание
2 файл не найден
3 путь не найден
4 слишком много открытых файлов
5 отказано в доступе
12 неверный режим доступа
15 неправильный номер диска
16 нельзя удалять текущую директорию
100 ошибка при чтении с диска
101 ошибка при записи на диск
102 не применена процедура AssignFile
103 файл не открыт
104 файл не открыт для ввода
105 файл не открыт для вывода
106 неверный номер
150 диск защищён от записи

Рассмотрим несколько практических примеров обработки ошибок ввода-вывода:

  1. При открытии проверить, существует ли заданный файл и возможно ли чтение данных из него.
    assign ( f, ’ abc. dat ’ );
    {$I-}
    reset ( f );
    {$I+}
    if IOResult<>0 then
    writeln ( ’файл не найден или не читается ’ )
    else
    begin
    read ( f,... );
    close ( f );
    end;
    
  2. Проверить, является ли вводимое с клавиатуры число целым.
    var i : integer;
    begin
    {$I-}
    repeat
    write ( ’введите целое число  i ’ );
    readln ( i );
    until ( IOResult =0);
    {$I+}
    {Этот цикл повторяется до тех пор, пока не будет введено целое число.}
    end.
    

При работе с текстовым файлом необходимо помнить специальные правила чтения значений переменных:

  • Когда вводятся числовые значения, два числа считаются разделёнными, если между ними есть хотя бы один пробел, или символ табуляции, или символ конца строки.
  • При вводе строк начало текущей строки идёт сразу за последним, введённым до этого символом. Вводится количество символов, равное объявленной длине строки. Если при чтении встретился символ «конец строки», то работа с этой строкой заканчивается. Сам символ конца строки является разделителем и в переменную никогда не считывается.
  • Процедура readln считывает значения текущей строки файла, курсор переводится в новую строку файла, и дальнейший ввод осуществляется с неё.

В качестве примера работы с текстовыми файлами рассмотрим следующую задачу.

ЗАДАЧА 7.8. В текстовом файле abc.txt находятся матрицы A(N, M ) и B(N, M ) и их размеры. Найти матрицу C = A + B, которую дописать в файл abc.txt.

Сначала создадим текстовый файл abc.txt следующей структуры: в первой строке через пробел хранятся размеры матрицы (числа N и M), затем построчно хранятся матрицы A и B.

Файл abc.txt

Рис.
7.14.
Файл abc.txt

На рис. 7.14 приведён пример файла abc.txt, в котором хранятся матрицы A(4,5) и B(4,5).

Текст консольного приложения решения задачи 7.8 с комментариями приведён ниже.

program Project1;
{$mode objfpc}{$H+}
uses
	Classes, SysUtils
	{ you can add units after this };
var
	f : Text;
	i, j, N,M: word;
	a, b, c : array [ 1.. 1000, 1.. 1000 ] of real;
begin
//Связываем файловую переменную f с файлом на диске.
	AssignFile ( f, ’ abc. t x t ’ );
//Открываем файл в режиме чтения.
	Reset ( f );
//Считываем из первой строки файла abc.txt значения N и M.
	Read( f,N,M);
//Последовательно считываем элементы матрицы А из файла.
	for i :=1 to N do
	for j :=1 to M do
	read ( f, a [ i, j ] );
//Последовательно считываем элементы матрицы B из файла.
	for i :=1 to N do
	for j :=1 to M do
	read ( f, b [ i, j ] );
//Формируем матрицу C=A+B.
	for i :=1 to N do
	for j :=1 to M do
	c [ i, j ] : = a [ i, j ]+b [ i ] [ j ];
//Закрываем файл f.
	CloseFile ( f );
//Открываем файл в режиме дозаписи.
	Append( f );
//Дозапись матрицы C в файл.
	for i :=1 to N do
	begin
		for j :=1 to M do
//Дописываем в файл очередной элемент матрицы и пробел в
//текстовый файл.
		write ( f, c [ i, j ] : 1 : 2, ’   ’ );
//По окончании вывода строки матрицы переходим на новую
//строку в текстовом файле.
		writeln ( f );
	end;
//Закрываем файл.
	CloseFile ( f );
end.

После работы программы файл abc.txt будет примерно таким, как показано на рис. 7.15.

Файл abc.txt после дозаписи матрицы C

Рис.
7.15.
Файл abc.txt после дозаписи матрицы C

В этом разделе обсуждаются разнообразные,
важные в практическом отношении, примемы
программирования.

1. Обработка ошибок ввода-вывода

В одном из предыдущих разделов был рассмотрен
фрагмент программы, демонстрирующий контроль за
вводимой информацией и не допускающий ввод
некорректных данных. Повторим здесь этот
фрагмент:

PROGRAM CheckInputData_1;
USES CRT;
VAR
  x : Real;
BEGIN
  ClrScr;
  REPEAT
    Write(‘Введите число в интервале от 0 до
100: ‘);
    Read(x);
    if not((x>=0)and(x<=100))
      then writeln(‘Ошибка при вводе
числа!’);
  UNTIL (x>=0)and(x<=100);
  …
  …
END.

Приведенная программа не допускает ввода числа
меньше нуля или больше ста. А что произойдет, если
вместо числа ввести (случайно) какой-либо иной
символ? Скорее всего это приведет к
возникновению фатальной (т.е. ведущий к
прекращению работы программы) ошибки
ввода-вывода:
Error 106: Invalid numeric format. Этого можно избежать, если
воспользоваться приемом, описанным ниже.

Сначала немного теории. Компилятор
языка Турбо Паскаль позволяет генерировать
выполнимый (машинный
) код в
дух режимах: с проверкой корректности
ввода-вывода и без нее. В среде программирования
этот режим включается в меню
Options – Compiler –
I/O Checking
. Режимом компиляции
можно управлять непосредственно в тексте
программы с помощью ключа компиляции
$I

{$I+} – режим проверки включен;
{$I-} – режим отключен.

По умолчанию, как правило, действует режим $I+. Этот ключ компиляции имеет
локальную сферу влияния. Можно многократно
включать и выключать режим, вставляя в текст
программы конструкции
{$I+} и {$I-},
тем самым создавая области с
контролем ввода-вывода и без него.

При включенном режиме проверки любая ошибка
ввода-вывода будет фатальной: программа
прервется, выдав номер ошибки. Если отключить
режим проверки, то при возникновении ошибки
ввода-вывода программа уже не будет прерываться,
а продолжит работу со следующего оператора.
Результат операции ввода-вывода, вызвавший
ошибку, будет неопределен. При этом код ошибки
будет сохранен и в последствии его можно узнать с
помощью специальной функции
IOResult. Эта функция возвращает целое число,
соответствующее коду последней ошибки
ввода-вывода. Если же операция ввода-вывода
прошла без сбоев, то функция вернет значение
0. Опросить функцию IOResult можно только один раз, ибо она
обнуляет свое значение при каждом вызове. Обычно
это обходят запоминанием значения функции в
какой-либо переменной.

Итак, для того чтобы рассмотренная выше
программа не давала сбоев при вводе, необходимо
отключить режим проверки ошибок
ввода-вывода на время работы
процедуры
Read, а затем
проанализировать значение функции
IOResult:

PROGRAM CheckInputData_2;
USES CRT;
VAR
    x : Real;

  err : Integer;
BEGIN
  ClrScr;
  REPEAT
  Write(‘Введите число в интервале от 0 до 100: ‘);

  {$I-}
    Read(x);

  {$I+}
  err := IOResult;
  if not((x>=0) and (x<=100)) or (err<>0)
    then writeln(‘Ошибка при вводе числа!’);
  UNTIL (x>=0) and (x<=100) and (err=0);
  …
  …
END.


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


2. Управление программой с помощью меню

При написании больших и не очень больших
программ, выполняющих различные действия,
полезно сделать так, чтобы у пользователя была
возможность выбрать тот или иной режим работы с
программой. Например, если программа направлена
на решение некоторой физической задачи, то она
может иметь по крайней мере три режима работы: 1)
ввод и модификация параметров задачи; 2)
собственно вычисления; 3) представление
результатов (например, построение графиков
рассчитанных зависимостей). Организация выбора
режимов работы может быть сделана с помощью меню.
Меню, в данном случае, — это перечень команд или
режимов работы, которые можно выбрать тем или
иным способом. В простейшем случае, меню может
быть представлено на экране нумерованным
списком. Выбор того или иного пункта
меню осуществляется вводом числа,
соответствующего номеру пункта. В более сложных
случаях выбор пункта меню может осуществляться
перемещением (с помощью клавиатуры или “мыши”)
курсора-подсветки, а активизация выбранного
пункта – нажатием на клавишу “
Enter” или щелчком кнопки мыши.

Рассмотрим в качестве примера структуру
программы, содержащей простейшее меню в виде
нумерованного списка.

PROGRAM Example_of_Menu;
USES CRT;
VAR Ch : Char;

PROCEDURE ChangeParam;
BEGIN
END;



PROCEDURE Calculation;
BEGIN
END;


PROCEDURE ShowGraphic;
BEGIN
END;

BEGIN
  repeat
    ClrScr;
    GotoXY(30,2);
    Write(‘НАЗВАНИЕ ПРОГРАММЫ’);
    GotoXY(28,6);
    Write(‘- Меню режимов работы -’);
    GotoXY(20,8);  Write(‘1 — Ввод и изменение
параметров’);
    GotoXY(20,10); Write(‘2 — Вычисление’);
    GotoXY(20,12); Write(‘3 — Построение графика’);
    GotoXY(20,14); Write(‘4 — Завершение работы’);
    GotoXY(15,18);
    Write(‘Для выбора режима работы нажмите
клавишу [1..4]: ’);
    repeat
      Ch := ReadKey;
    until Ch in [’1’,’2’,’3’,’4’];
    case Ch of
     ‘1’ : ChangeParam;
     ‘2’ : Calculation;
     ’3’ : ShowGraphic;
     ’4’ : Halt;


    end; {case}
  until false;

END.

Права на материал принадлежат их авторам
Вернуться на главную страницу

Понравилась статья? Поделить с друзьями:
  • Обработка ошибки в свойстве ошибка access
  • Обработка ошибок в си шарп
  • Обработка ошибки pdo в php
  • Обработка ошибок в сети frame relay
  • Обработка ошибки 404 в php