Midass 0 / 0 / 0 Регистрация: 10.09.2015 Сообщений: 34 |
||||
1 |
||||
Ошибка ввода — программа завершена15.09.2015, 19:58. Показов 5188. Ответов 6 Метки нет (Все метки)
Пишет: »*Ошибка ввода. Программа завершена (Program3.pas, строка 6)
0 |
ФедосеевПавел Модератор 8324 / 4223 / 1602 Регистрация: 01.02.2015 Сообщений: 13,154 Записей в блоге: 4 |
||||
15.09.2015, 21:25 |
2 |
|||
Ваш отформатированный код
Очевидно, что будут выполнятся только ветка » if (x > -5) or (x <> 0) then».
1 |
Почетный модератор 64289 / 47588 / 32739 Регистрация: 18.05.2008 Сообщений: 115,181 |
|
15.09.2015, 21:30 |
3 |
Что вы вводите? Нужно условие задачи глянуть, тут лажа написана…
1 |
0 / 0 / 0 Регистрация: 10.09.2015 Сообщений: 34 |
|
15.09.2015, 21:41 [ТС] |
4 |
Вот условие: Виды функций: Исходные данные: X=-18.76; X=-3.57; X=-7.15.
0 |
Модератор 8324 / 4223 / 1602 Регистрация: 01.02.2015 Сообщений: 13,154 Записей в блоге: 4 |
|
15.09.2015, 21:50 |
5 |
if (x > -5)
and (x <> 0) then
1 |
Puporev Почетный модератор 64289 / 47588 / 32739 Регистрация: 18.05.2008 Сообщений: 115,181 |
||||
15.09.2015, 21:50 |
6 |
|||
Сообщение было отмечено Памирыч как решение РешениеЕсли как написано на картинке, то так.
1 |
Модератор 8324 / 4223 / 1602 Регистрация: 01.02.2015 Сообщений: 13,154 Записей в блоге: 4 |
|
15.09.2015, 21:51 |
7 |
И ещё — в ветках if достаточно вычислять. Вывод writeln — можно сделать после вычисления перед последним end. Как это показано у Puporev.
1 |
Midass 0 / 0 / 0 Регистрация: 10.09.2015 Сообщений: 34 |
||||
1 |
||||
Ошибка ввода — программа завершена15.09.2015, 19:58. Показов 4790. Ответов 6 Метки нет (Все метки)
Пишет: »*Ошибка ввода. Программа завершена (Program3.pas, строка 6)
__________________ 0 |
ФедосеевПавел Модератор 8276 / 4180 / 1595 Регистрация: 01.02.2015 Сообщений: 12,994 Записей в блоге: 3 |
||||
15.09.2015, 21:25 |
2 |
|||
Ваш отформатированный код
Очевидно, что будут выполнятся только ветка » if (x > -5) or (x <> 0) then». 1 |
Почетный модератор 64270 / 47569 / 32739 Регистрация: 18.05.2008 Сообщений: 115,182 |
|
15.09.2015, 21:30 |
3 |
Что вы вводите? Нужно условие задачи глянуть, тут лажа написана… 1 |
0 / 0 / 0 Регистрация: 10.09.2015 Сообщений: 34 |
|
15.09.2015, 21:41 [ТС] |
4 |
Вот условие: Виды функций: Исходные данные: X=-18.76; X=-3.57; X=-7.15. 0 |
Модератор 8276 / 4180 / 1595 Регистрация: 01.02.2015 Сообщений: 12,994 Записей в блоге: 3 |
|
15.09.2015, 21:50 |
5 |
if (x > -5)
and (x <> 0) then 1 |
Puporev Почетный модератор 64270 / 47569 / 32739 Регистрация: 18.05.2008 Сообщений: 115,182 |
||||
15.09.2015, 21:50 |
6 |
|||
Сообщение было отмечено Памирыч как решение РешениеЕсли как написано на картинке, то так.
1 |
Модератор 8276 / 4180 / 1595 Регистрация: 01.02.2015 Сообщений: 12,994 Записей в блоге: 3 |
|
15.09.2015, 21:51 |
7 |
И ещё — в ветках if достаточно вычислять. Вывод writeln — можно сделать после вычисления перед последним end. Как это показано у Puporev. 1 |
Неописанная переменная
begin S := 1; // Неизвестное имя S end.
Все используемые переменные должны быть предварительно описаны с помощью ключевого слова var (внутри блока begin/end или, что обычно хуже, в разделе описаний вначале программы).
Отсутствующая ;
begin var S: integer S := 1; // Компилятор здесь скажет: Ожидалась ; — имеется ввиду предыдущая строка! end.
begin var S := 1 S := S + 1 // Аналогично: проблема на предыдущей строке, а на текущей нет, потому что после неё идёт end. end.
Очень частая ошибка у начинающих. Курсор, как правило, позиционируется в начале следующей строки.
Несовместимость типов при присваивании
begin var S: integer := 1.3; // Нельзя преобразовать тип real к integer end.
Безболезненно можно присваивать только данные одного типа. Если данные — разных типов, то в редких случаях можно преобразовать данные одного типа в данные другого. Например, целое можно преобразовать в вещественное, а символ — в строку. Обратные преобразования не допускаются.
Чтобы не ошибаться в подобных простых случаях в Паскале есть следующая краткая форма объявления и инициализации переменной:
begin var S := 1.3; // Тип real будет выведен компилятором автоматически end.
Отсутствие закрывающего апострофа литеральной строки
begin var x := 2; // x получает тип integer var y := 3; // y получает тип integer writeln('Результат сложения равен =, x + y); // Не хватает закрывающего апострофа end.
Закрыть апостроф надо на той же строке, где расположен открывающий апостроф
Ошибки расстановки запятых и апострофов при выводе строк и выражений
begin var x := 2; // x получает тип integer var y := 3; // y получает тип integer writeln(x, '+,' y, '=', x+y); // Неверная расстановка запятых и апострофов end.
Слишком много запятых и апострофов рядом, потому начинающие часто путаются
Надо уяснить правила:
- запятые разделяют разные элементы вывода
- все, что находится в апострофах, будет выведено на экран без изменений
Ошибка ввода
begin var x: integer; read(x); // введите блаблабла и посмотрите, что получится end.
Это — ошибка во время выполнения. Программа пытается преобразовать введенную строку в число, не может это сделать и завершается с ошибкой.
Аналогичный фрагмент в более современном и предпочтительном синтаксисе:
begin var x := ReadInteger; end.
Ошибка неинициализированной переменной
begin var x: integer; // Забыли инициализировать или ввести x var r := x * x; // r получает тип integer writeln('Квадрат числа ', x, ' = ', r); end.
Перед использованием любую переменную надо ввести или присвоить ей начальное значение. Это действие называется инициализацией переменной.
Деление на 0
begin var x := 0; var c := 666 div x; // Здесь происходит деление на 0 end.
Если во время выполнения программа выполнит деление на 0, то она завершится с ошибкой.
Корень из отрицательного числа
begin writeln(sqrt(-1)); // Корень из отрицательного числа end.
В обычном Паскале возникает ошибка времени выполнения.
В PascalABC.NET выводится NaN — Not a Number
Ссылки
- Программы для начинающих
- Сайт PascalABC.NET: Программы и алгоритмы для начинающих
Компилятор Паскаля – сложное приложение,
имеющее множество настроек. При написании
учебных программ большинство этих
настроек не имеют значения, но некоторые
из них окажутся нам полезны. Для управления
компилятором существует 2 основных
возможности: настройка режимов работы
с помощью верхнего меню OptionsоболочкиTurboPascalи настройка конкретной программы с
помощьюдиректив компилятора,
которую мы кратко рассмотрим. В общем
виде директива компилятора представляет
собой конструкцию вида{$X+}или{$X-},гдеX– латинская буква. Вариант со знаком
«+»
включает некоторый режим работы
компилятора (например, строгий контроль
программой соответствия типов данных,
вывод системных диагностических
сообщений и т.д.), а вариант со знаком
«-»
выключает его. Расположение директив,
в общем, произвольно, однако, директивы,
влияющие на всю программу, принято
располагать в самом начале файла с
исходным текстом. Фигурные скобки
комментария{
… }необходимы, чтобы скрыть
действие директив от старых версий
компилятора, которые не умели их
распознавать.
Подробную информацию о назначении всех
директив можно получить в справочной
системе оболочки. Основные директивы
компилятора также кратко описаны в
Приложении 2.
Наиболее полезной для нас выглядит
директива {$I-}/{$I+},
соответственно, выключающая и включающая
автоматический контроль программой
результатов операций ввода/вывода
(в/в). К операциям в/в относятся, в числе
прочего, ввод данных пользователем,
вывод строки на принтер, открытие файла
для получения или вывода данных и т.п.
Понятно, что даже несложная учебная
программа выглядит лучше, если она умеет
реагировать на неправильные действия
пользователя или возникающие ошибки
не просто выводом маловразумительного
системного сообщения на английском
языке, а доступным неискушенному
пользователю текстом. По умолчанию
контроль в/в включен и системные сообщения
об ошибках генерируются автоматически.
Все они кратко приведены в Приложении
3. Для замены системной диагностики
своей собственной следует, во-первых,
отключить директиву контроля оператором{$I-},
а во-вторых, сразу же после оператора,
который мог породить ошибку, проверить
значение, возвращаемое системной
функциейIoResult.
Эта функция возвращаетноль, если
последняя операция в/в прошлауспешно,
в противном случае возвращается ненулевое
значение. После завершения «критического»
оператора директиву следует включить
снова, чтобы не создавать потенциально
опасных ситуаций в коде, который будет
писаться далее! Приведем один пример,
написав «расширенную» программу
решения квадратного уравнения, корректно
реагирующую на возникающие ошибки:
uses printer;
var a,b,c,d,x1,x2:real;
begin
writeln;
writeln (‘Введите 3
вещественных числа:’);
{$I-} read
(a,b,c); {$I+}
if
IoResult<>0 then begin {Возникла
ошибка!}
Writeln (‘Вы не ввели
3 числа, это что-то другое!’);
Reset (input); {очищаем
буфер клавиатуры перед ожиданием
нажатия Enter}
Readln;
Halt; {а этим оператором
можно аварийно завершить программу!}
end;
d:=sqr(b)-4*a*c;
if d<0 then begin
Writeln (‘Ошибка при
вычислении корней — дискриминант<0’);
Reset
(input);
Readln;
Halt;
end;
x1:=(-b+sqrt(d))/(2*a);
x2:=(-b-sqrt(d))/(2*a);
{$I-}
writeln (lst,’x1=’,x1:8:2,’
x2=’,x2:8:2);
{$I+}
if IoResult<>0 then
Writeln (‘Не удалось вывести на принтер’)
else Writeln (‘Результаты
напечатаны’);
Reset (input); {Перед
Readln
очистили стандартный поток ввода}
Readln;
Halt;
end.
Специальной директивы для контроля
математических ошибок в Паскале не
предусмотрено, но это почти всегда можно
сделать обычными проверками корректности
данных. Обратите внимание на альтернативное
решение проблемы «двух readln»
в этом коде, а также на новый операторHaltи способ
контроля того, удалось ли вывести строку
на принтер.
В дальнейшем мы не всегда будем выполнять
подобные проверки, однако, их никогда
не помешает делать, если Вы хотите
создать удобные для пользователя и
понятные для разработчика программы.
Для работы с вещественными числами с
двойной точностью (тип double)
может также понадобиться указать перед
программой директиву{$N+},
позволяющую сгенерировать код для
аппаратной обработки таких чисел.
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
1 Out of memory (Выход за границы памяти). 2 Identifier expected (Не указан идентификатор). 3 Unknown identifier (Неизвестный идентификатор). 4 Duplicate identifier (Двойной идентификатор). 5 Syntax error (Синтаксическая ошибка). 6 Error in real constant (Ошибка в вещественной константе). 7 Error in integer constant (Ошибка в целой константе). 8 String constant exceeds line (Строковая константа превышает допустимые размеры). 9 Too many nested files (Слишком много вложенных файлов). 10 Unexpected end of file (He найден конец файла). 11 Line too long (Слишком длинная строка) 12 Type identifier expected (Здесь нужен идентификатор типа). 13 Too many open files (Слишком много открытых файлов). 14 Invalid file name (Неверное имя файла). 15 File not found (Файл не найден). 16 Disk full (Диск заполнен). 17 Invalid compiler directive (Неправильная директива компилятора). 18 Too many files (Слишком много файлов). 19 Undefined type in pointer definition (Неопределенный тип в объявлении указателя). 20 Variable identifier expected (Отсутствует идентификатор переменной). 21 Error in type (Ошибка в объявлении типа). 22 Structure too large (Слишком большая структура). 23 Set base type of range (Базовый тип множества нарушает границы). 24 File components may not be files (Компонентами файла не могут быть файлы) . 25 Invalid string length (Неверная длина строки). 26 Type mismatch (Несоответствие типов). 27 Invalid subrange base type (Неправильный базовый тип для типа-диапазона). 28 Lower bound greater than upper bound (Нижняя граница больше верхней). 29 Ordinal type expected (Нужен порядковый тип). 30 Integer constant expected (Нужна целая константа). 31 Constant expected (Нужна константа). 32 Integer or real constant expected (Нужна целая или вещественная константа) . 33 Type identifier expected (Нужен идентификатор типа) 34 Invalid function result type (Неправильный тип результата функции) 35 Label identifier expected (Нужен идентификатор метки). 36 BEGIN expected (Нужен BEGIN). 37 END expected (Нужен END). 38 Integer expression expected (Нужно выражение типа INTEGER). 39 Ordinal expression expected (Нужно выражение перечисляемого типа). 40 Boolean expression expected (Нужно выражение типа BOOLEAN). 41 Operand types do not match operator (Типы операндов не соответствуют операции). 42 Error in expression (Ошибка в выражении). 43 Illegal assignment (Неверное присваивание). 44 Field identifier expected (Нужен идентификатор поля) . 45 Object file too large (Объектный файл слишком большой). 46 Undefined external (Неопределенная внешняя процедура). 47 Invalid object file record (Неправильная запись объектного файла). 48 Code segment too large (Сегмент кода слишком большой). 49 Data segment too large (Сегмент данных слишком велик). 50 DO expected (Нужен оператор DO). 51 Invalid PUBLIC definition (Неверное PUBLIC-определение). 52 Invalid EXTRN definition (Неправильное EXTRN-определение). 53 Too many EXTRN definition (Слишком много EXTRN-определений). 54 OF expected (Требуется OF). 55 INTERFACE expected (Требуется интерфейсная секция). 56 Invalid relocatable reference (Неправильная перемещаемая ссылка). 57 THEN expected (Требуется THEN). 58 TO or DOWNTO expected (Требуется TO или DOWNTO). 59 Undefined forward (Неопределенное опережающее описание). 60 Too many procedures (Слишком много процедур). 61 Invalid typecast (Неверное преобразование типа). 62 Division by zero (Деление на ноль). 63 Invalid file type (Неверный файловый тип). 64 Cannot Read or Write variables of this type (Нет возможности считать или записать переменные данного типа). 65 Pointer variable expected (Нужно использовать переменную-указатель). 66 String variable expected (Нужна строковая переменная). 67 String expression expected (Нужно выражение строкового типа). 68 Circular unit reference (Перекрестная ссылка модулей). 69 Unit name mismatch (Несоответствие имен программных модулей). 70 Unit version mismatch (Несоответствие версий модулей). 71 Duplicate unit name (Повторное имя программного модуля). 72 Unit file format error (Ошибка формата файла модуля). 73 IMPLEMENTATION expected (Отсутствует исполняемая часть модуля). 74 Constant and case types do not match (Типы констант и тип выражения опе- ратора CASE не соответствуют друг другу). 75 Record variable expected (Нужна переменная типа запись). 76 Constant out of range (Константа нарушает границы). 77 File variable expected (Нужна файловая переменная). 78 Pointer expression expected (Нужно выражение типа указатель). 79 Integer or real expression expected (Нужно выражение вещественного или целого типа). 80 Label not within current block (Метка не находится внутри текущего блока) 81 Label already defined (Метка уже определена). 82 Undefined label in processing statement part (Неопределенная метка в предшествующем разделе операторов). 83 Invalid @ argument (Неправильный аргумент операции @). 84 Unit expected (Нужно кодовое слово UNIT). 85 ”;” expected (Нужно указать”;”). 86 ”:” expected (Нужно указать”:”). 87 ”,”expected (Нужно указать”,”). 88 ”(” expected (Нужно указать ”(”). 89 ”)” expected (Нужно указать”)”). 90 ”=” expected (Нужно указать”=”) 91 ”:=” expected (Нужно указать”:=”) 92 ”[” or ”(.”expected (Нужно указать ”[” или ”(.”). 93 ”]” or ”.)” expected (Нужно указать”]” или ”.)”). 94 ”.” expected (Нужно указать”.”) 95 ”..” expected (Нужно указать”..”). 96 Too many variables (Слишком много переменных). 97 Invalid FOR control variable (Неправильный параметр цикла оператора FOR). 98 Integer variable expected (Нужна переменная целого типа). 99 File and procedure types are not allowed here (Здесь не могут использоваться файлы или процедурные типы). 100 String length mismatch (Несоответствие длины строки). 101 Invalid ordering of fields (Неверный порядок полей). 102 String constant expected (Нужна константа строкового типа). 103 Integer or real variable expected (Нужна переменная типа INTEGER или REAL). 104 Ordinal variable expected (Нужна переменная порядкового типа). 105 INLINE error (Ошибка в операторе INLINE) 106 Character expression expected (Предшествующее выражение должно иметь символьный тип). 107 Too many relocation items (Слишком много перемещаемых элементов). 108 Overflow in arithmetic operator (Переполнение при выполнении арифметического оператора). 109 No enclosing FOR, WHILE or REPEAT statement (Нет операторов, заканчивающих операторы FOR, WHILE или REPEAT). 110 Debug information table overflow (Переполнение информационной таблицы отладки) 111 N/A 112 CASE constant out of range (Константа CASE нарушает допустимые границы) . 113 Error in statement (Ошибка в операторе). 114 114 Cannot call an interrupt procedure (Невозможно вызвать процедуру npерывания). 115 N/A 116 Must be in 8087 mode to compile this (Для компиляции необходим режим 8087). 117 Target address not found (Указанный адрес не найден). 118 118 Include files are not allowed here (Здесь не допускаются включаемые файлы). 119 No inherited methods are accessible here (В этом месте программы нет унаследованных методов). 120 N/A 121 Invalid qualifier (Неверный квалификатор). 122 Invalid variable reference (Недействительная ссылка на переменную). 123 Too many symbols (Слишком много символов). 124 Statement part too large (Слишком большой раздел операторов). 125 N/A 126 Files must be var parameters (Файлы должны передаваться как параметры-переменные). 127 Too many conditional symbols (Слишком много условных символов). 128 Misplaced conditional directive (Пропущена условная директива). 129 ENDIF directive missing (Пропущена директива ENDIF). 130 Error in initial conditional defines (Ошибка в условных определениях). 131 Header does not match previous definition (Заголовок не соответствует предыдущему определению). 132 Critical disk error (Критическая ошибка диска). 133 Cannot evaluate this expression (Нельзя вычислить данное выражение). 134 Expression incorrectly germinated (Некорректное завершение выражения). 135 Invalid format specifier (Неверный спецификатор формата). 136 Invalid indirect reference (Недопустимая косвенная ссылка). 137 Structured variable are not allowed here (Здесь нельзя использовать переменную структурного типа). 138 Cannot evaluate without System unit (Нельзя вычислить выражение без мо-дуля SYSTEM). 139 Cannot access this symbol (Нет доступа к данному символу). 140 Invalid floating-point operation (Недопустимая операция с плавающей запятой). 141 Cannot compile overlay to memory (Нельзя выполнить компиляцию оверлейных модулей в память). 142 Procedure or function variable expected (Должна использоваться перемен- ная процедурного типа). 143 Invalid procedure or function reference (Недопустимая ссылка на процедуру или функцию) . 144 Cannot overlay this unit (Этот модуль не может использоваться в качестве оверлейного). 145 Too many nested scopes (Слишком много вложений). 146 File access denied (Отказано в доступе к файлу). 147 Object type expected (Здесь должен быть тип OBJECT) . 148 object types are not allowed (Нельзя объявлять локальные объекты). 149 VIRTUAL expected (Пропущено слово VIRTUAL). 150 Method identifier expected (Пропущен идентификатор инкапсулированного правила). 151 Virtual constructor are not allowed (Конструктор не может быть виртуальным). 153 Destructor identifier expected (Пропущен идентификатор деструктора). 154 Fail only allowed within constructor (Обращение к стандартной процедуре FAIL может содержаться только в конструкторе). 155 Invalid combination of opcode and operands (Недопустимая комбинация кода команды и операндов). 156 Memory reference expected (Отсутствует адрес). 157 Cannot add or subtract relocatable symbols (Нельзя складывать или вычитать перемещаемые символы). 158 Invalid register combination (Недопустимая комбинация регистров). 159 286/287 instructions are not enabled (Недоступен набор команд микропроцессоров 286/287). 160 Invalid symbol reference (Недопустимая ссылка на символ). 161 Code generation error (Ошибка генерации кода). 162 ASM expected (Отсутствует зарезервированное слово ASM).
7.4 Обработка текстовых файлов в языке Free Pascal
При работе с текстовыми файлами следует учесть следующее:
- Действие процедур reset, rewrite, close, rename, erase и функции eof аналогично их действию при работе с компонентными (типизированными) файлами.
- Процедуры seek, trunсate и функция filepos не работают с текстовыми файлами.
- Можно пользоваться процедурой открытия текстового файла append(f), где f — имя файловой переменной. Эта процедура служит для открытия файла в режиме дозаписи в конец файла. Она применима только к уже физически существующим файлам, открывает и готовит их для добавления информации в конец файла.
- Запись и чтение в текстовый файл осуществляются с помощью процедур 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 | диск защищён от записи |
Рассмотрим несколько практических примеров обработки ошибок ввода-вывода:
- При открытии проверить, существует ли заданный файл и возможно ли чтение данных из него.
assign ( f, ’ abc. dat ’ ); {$I-} reset ( f ); {$I+} if IOResult<>0 then writeln ( ’файл не найден или не читается ’ ) else begin read ( f,... ); close ( f ); end;
- Проверить, является ли вводимое с клавиатуры число целым.
var i : integer; begin {$I-} repeat write ( ’введите целое число i ’ ); readln ( i ); until ( IOResult =0); {$I+} {Этот цикл повторяется до тех пор, пока не будет введено целое число.} end.
При работе с текстовым файлом необходимо помнить специальные правила чтения значений переменных:
- Когда вводятся числовые значения, два числа считаются разделёнными, если между ними есть хотя бы один пробел, или символ табуляции, или символ конца строки.
- При вводе строк начало текущей строки идёт сразу за последним, введённым до этого символом. Вводится количество символов, равное объявленной длине строки. Если при чтении встретился символ «конец строки», то работа с этой строкой заканчивается. Сам символ конца строки является разделителем и в переменную никогда не считывается.
- Процедура readln считывает значения текущей строки файла, курсор переводится в новую строку файла, и дальнейший ввод осуществляется с неё.
В качестве примера работы с текстовыми файлами рассмотрим следующую задачу.
ЗАДАЧА 7.8. В текстовом файле abc.txt находятся матрицы и и их размеры. Найти матрицу , которую дописать в файл abc.txt.
Сначала создадим текстовый файл abc.txt следующей структуры: в первой строке через пробел хранятся размеры матрицы (числа N и M), затем построчно хранятся матрицы A и B.
Рис.
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.
Рис.
7.15.
Файл abc.txt после дозаписи матрицы C
│
العربية (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
7.4 Обработка текстовых файлов в языке Free Pascal
При работе с текстовыми файлами следует учесть следующее:
- Действие процедур reset, rewrite, close, rename, erase и функции eof аналогично их действию при работе с компонентными (типизированными) файлами.
- Процедуры seek, trunсate и функция filepos не работают с текстовыми файлами.
- Можно пользоваться процедурой открытия текстового файла append(f), где f — имя файловой переменной. Эта процедура служит для открытия файла в режиме дозаписи в конец файла. Она применима только к уже физически существующим файлам, открывает и готовит их для добавления информации в конец файла.
- Запись и чтение в текстовый файл осуществляются с помощью процедур 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 | диск защищён от записи |
Рассмотрим несколько практических примеров обработки ошибок ввода-вывода:
- При открытии проверить, существует ли заданный файл и возможно ли чтение данных из него.
assign ( f, ’ abc. dat ’ ); {$I-} reset ( f ); {$I+} if IOResult<>0 then writeln ( ’файл не найден или не читается ’ ) else begin read ( f,... ); close ( f ); end;
- Проверить, является ли вводимое с клавиатуры число целым.
var i : integer; begin {$I-} repeat write ( ’введите целое число i ’ ); readln ( i ); until ( IOResult =0); {$I+} {Этот цикл повторяется до тех пор, пока не будет введено целое число.} end.
При работе с текстовым файлом необходимо помнить специальные правила чтения значений переменных:
- Когда вводятся числовые значения, два числа считаются разделёнными, если между ними есть хотя бы один пробел, или символ табуляции, или символ конца строки.
- При вводе строк начало текущей строки идёт сразу за последним, введённым до этого символом. Вводится количество символов, равное объявленной длине строки. Если при чтении встретился символ «конец строки», то работа с этой строкой заканчивается. Сам символ конца строки является разделителем и в переменную никогда не считывается.
- Процедура readln считывает значения текущей строки файла, курсор переводится в новую строку файла, и дальнейший ввод осуществляется с неё.
В качестве примера работы с текстовыми файлами рассмотрим следующую задачу.
ЗАДАЧА 7.8. В текстовом файле abc.txt находятся матрицы и и их размеры. Найти матрицу , которую дописать в файл abc.txt.
Сначала создадим текстовый файл abc.txt следующей структуры: в первой строке через пробел хранятся размеры матрицы (числа N и M), затем построчно хранятся матрицы A и B.
Рис.
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.
Рис.
7.15.
Файл abc.txt после дозаписи матрицы C
Компилятор Турбо Паскаля позволяет генерировать выполнимый код в двух режимах: с проверкой корректности ввода-вывода и без нее. В среде программирования этот режим включается в меню
— 262 —
Options/Compiler/IO-checking. При включении в программу ключ режима компиляции обозначается как
{$I+} — режим проверки включен;
{$I-} — режим отключен.
По умолчанию, как правило, действует режим $I+. Этот ключ компиляции имеет локальную сферу влияния. Можно многократно включать и выключать режим, вставляя в текст программы конструкции {$I+} и {SI-}, тем самым создавая области с контролем ввода-вывода и без него.
При включенном режиме проверки любая ошибка ввода-вывода будет фатальной: программа прервется, выдав номер ошибки. Возможные номера ошибок ввода-вывода находятся в диапазоне от 2 до 200 ( от 2 до 99 — это коды ошибок DOS, от 100 до 149 — ошибки, диагностируемые самой программой, и от 150 до 200 — критические аппаратные ошибки). Расшифровка кодов ошибок с краткими комментариями приведена в табл. 12.6 в конце этого раздела.
Если отключить режим проверки, то при возникновении ошибки ввода-вывода программа уже не будет прерываться, а продолжит работу со следующего оператора. Результат операции ввода-вывода, вызвавшей ошибку, будет неопределен. При этом код ошибки будет сохранен в предопределенной системной переменной InOutRes. Однако для опроса этого кода лучше пользоваться специальной функцией Турбо Паскаля.
Дополнительные функции работы с файлами
Модуль |
|
ChDir |
Выполняет |
MkDir |
Создает |
RmDir |
Удаляет |
GetDir |
Получить |
Модуль |
|
DiskFree |
Число |
DiskSize |
Размер |
GetFAttr |
Получение |
SetFAttr |
Задание |
FSplit |
Получение |
FExpand |
Формирование |
FSearch |
Поиск |
FindFirst |
Поиск |
FindNext |
Поиск |
Прототипы
процедур FindFirst
и FindNext
имеют вид:
FindFirst(Path:
String; Attrib: Word; Var SR: SearchRec);
FindNext(Var
SR:
SearchRec);
Для
работы с этими подпрограммами требуются
следующие предопределенные описания:
-
Константы
Const
ReadOnly
= $01; только
для чтения
Hidden = $02; скрытый
SysFile =
$04; системный (непереносимый)
Volume ID = $08; метка
диска
Directory =
$10; подкаталог
Archive = $20; архивный
AnyFile = $3F; сумма
всех предыдущих
Эти атрибуты можно
складывать или вычитать (из anyfile).
-
Переменная
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
<номер> <смещение>.
Такое сообщение
буде полезно вам как программистам при
поиске места и причины ошибки в программе.
Однако показывать такое сообщение
пользователю вашей программы будет не
совсем дружественно.
Для того, чтобы
ваша программа из-за ошибки аварийно
не завершалась и для того, чтобы не
пугать пользователей непонятными им
сообщениями, вам необходимо перехватить
инициативу по обработке ошибок у системы
и писать собственные обработчики ошибок
стадии выполнения (исключений). Традиционно
обработка ошибок в программах
осуществляется с помощью установки
флагов (в
случае ошибки) и последующего анализа
этих флагов. Для перехвата ошибок
ввода-вывода на Паскале необходимо:
-
Специальным
образом оформить каждый фрагмент
программы, которые потенциально могут
вызвать ошибку. К таким фрагментам
относятся — открытие файда, чтение из
файла, запись в файл. -
При наличии такого
специального оформления необходимо
по завершению фрагмента проверить:
была ошибка или нет. Если была, то вы
должны выполнить ее обработку (хотя бы
вывести свое сообщение).
Пример:
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
- #
- #
- #
- #
- #
- #
- #
- #
- #
- #
В этом разделе обсуждаются разнообразные,
важные в практическом отношении, примемы
программирования.
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.
Права на материал принадлежат их авторам
Вернуться на главную страницу
Неописанная переменная
begin S := 1; // Неизвестное имя S end.
Все используемые переменные должны быть предварительно описаны с помощью ключевого слова var (внутри блока begin/end или, что обычно хуже, в разделе описаний вначале программы).
Отсутствующая ;
begin var S: integer S := 1; // Компилятор здесь скажет: Ожидалась ; — имеется ввиду предыдущая строка! end.
begin var S := 1 S := S + 1 // Аналогично: проблема на предыдущей строке, а на текущей нет, потому что после неё идёт end. end.
Очень частая ошибка у начинающих. Курсор, как правило, позиционируется в начале следующей строки.
Несовместимость типов при присваивании
begin var S: integer := 1.3; // Нельзя преобразовать тип real к integer end.
Безболезненно можно присваивать только данные одного типа. Если данные — разных типов, то в редких случаях можно преобразовать данные одного типа в данные другого. Например, целое можно преобразовать в вещественное, а символ — в строку. Обратные преобразования не допускаются.
Чтобы не ошибаться в подобных простых случаях в Паскале есть следующая краткая форма объявления и инициализации переменной:
begin var S := 1.3; // Тип real будет выведен компилятором автоматически end.
Отсутствие закрывающего апострофа литеральной строки
begin var x := 2; // x получает тип integer var y := 3; // y получает тип integer writeln('Результат сложения равен =, x + y); // Не хватает закрывающего апострофа end.
Закрыть апостроф надо на той же строке, где расположен открывающий апостроф
Ошибки расстановки запятых и апострофов при выводе строк и выражений
begin var x := 2; // x получает тип integer var y := 3; // y получает тип integer writeln(x, '+,' y, '=', x+y); // Неверная расстановка запятых и апострофов end.
Слишком много запятых и апострофов рядом, потому начинающие часто путаются
Надо уяснить правила:
- запятые разделяют разные элементы вывода
- все, что находится в апострофах, будет выведено на экран без изменений
Ошибка ввода
begin var x: integer; read(x); // введите блаблабла и посмотрите, что получится end.
Это — ошибка во время выполнения. Программа пытается преобразовать введенную строку в число, не может это сделать и завершается с ошибкой.
Аналогичный фрагмент в более современном и предпочтительном синтаксисе:
begin var x := ReadInteger; end.
Ошибка неинициализированной переменной
begin var x: integer; // Забыли инициализировать или ввести x var r := x * x; // r получает тип integer writeln('Квадрат числа ', x, ' = ', r); end.
Перед использованием любую переменную надо ввести или присвоить ей начальное значение. Это действие называется инициализацией переменной.
Деление на 0
begin var x := 0; var c := 666 div x; // Здесь происходит деление на 0 end.
Если во время выполнения программа выполнит деление на 0, то она завершится с ошибкой.
Корень из отрицательного числа
begin writeln(sqrt(-1)); // Корень из отрицательного числа end.
В обычном Паскале возникает ошибка времени выполнения.
В PascalABC.NET выводится NaN — Not a Number
Ссылки
- Программы для начинающих
- Сайт PascalABC.NET: Программы и алгоритмы для начинающих
������� ��������� ����������
������� ��������� ����������
������ 1. ��������� ��������� ����� ������.
���������� ���������.
var i: integer;
begin
readln(i);
writeln(i);
writeln(‘���������� ��������� ������������’);
end.
���� ��� ����� ������ ���������� ������ (��������, �� ������ �� �����), �� ��������� ���������� � ������� (������ �����), � ����������� ��������� writeln �� ����� ���������.
���������� ���������� � ����� try:
var i: integer;
begin
try
readln(i);
writeln(i);
except
writeln(‘������ �����’);
end;
writeln(‘���������� ��������� ������������’);
end.
�� ���� ��� ��� ������������� ������ ����� ��������� �� ����� ���������, � ���������� ����� �������� � ���� except, ����� ���� ���������� ��������� ����������� ������. ����� �������, � ��������� ��������� �� ���������� ���� �������� writeln(i).
���� � ����� try ����� ���������� ��������� ����������, �� ������ ������������ ������ ����� ����� except � ����������� ������������� ����������.
������ 2. ��������� ��������� ����������.
var a,b: integer;
assign(f,’a.txt’);
try
readln(a,b);
reset(f);
c:=a div b;
except
on System.DivideByZeroException do
writeln(‘������������� ������� �� 0’);
on System.IO.IOException do
writeln(‘���� �����������’);
end;
����� ���������� ��������� ��������� ���������� � ������������ �������� ���������� �� ����, ��������� ���������� ��� ���. � ���� ������ ������������ ��������� ��������� try … except � try … finally.
������ 3. ��������� ��������� try … except � try … finally.
assign(f,’a.txt’);
try
reset(f);
try
try
c:=a div b;
except
on System.DivideByZeroException do
writeln(‘������������� ������� �� 0’);
end;
finally
close(f);
end;
except
on System.IO.IOException do
writeln(‘���� �����������’);
end;
������� ��������, ��� � ������ ������� ����������, ��������� c ������������� �������� �� 0, �������������� � ����� ���������� ����� try, � ����������, ��������� � ������������� ������ — � ����� �������. ��� ����, ���� ���� ��� ������, �� ���������� �� ������������� ���������� ������� �� 0 �� ����� ������.