/
n-dimens
/
pascalabcnet
Обзор
Документация
Войти
/
n-dimens
/
pascalabcnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
PABCNetHelp/ForEducation/CheckedTasks/ctfile.html
343 строки
21 KB
samuraiGH
adding working-tree-encoding attribute (#3325)
07 ноя 2025, 16:12
Не верифицирован
07 ноя 2025, 16:12
cf1fd29
Код
Авторство
О чём код?
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <title></title> <link rel="StyleSheet" href="../../default.css"> </head> <body> <H1>Задание на обработку файлов</H1> <hr> <h3>Создание программы-заготовки и знакомство с заданием</h3> <p>В качестве примера задания на обработку файлов рассмотрим задание File48.</p> <p>Напомним, что программу-заготовку для решения этого задания можно создать с помощью команды меню «Модули | Создать шаблон программы», кнопки <img border="0" src="gif/Load.gif" width="16" height="17"> или клавиатурной комбинации <b>Shift+Ctrl+L</b>. Эта заготовка будет иметь следующий вид: </p> <blockquote> <code><pre> <b>uses</b> PT4; <b>begin</b> Task('File48'); <b>end</b>.</pre></code> </blockquote> <p>После запуска данной программы на экране появится <a href="../PT4/window.html">окно задачника</a>:</p> <blockquote> <img border="0" src="gif/file48-1.png"> </blockquote> <p>В первой строке раздела исходных данных указаны имена трех исходных файлов (S<sub>A</sub>, S<sub>B</sub> и S<sub>C</sub>) и одного результирующего (S<sub>D</sub>). В последующих строках раздела исходных данных показано содержимое исходных файлов. Элементы файлов отображаются бирюзовым цветом, чтобы подчеркнуть их отличие от обычных исходных данных (желтого цвета) и комментариев (светло-серого цвета).</p> <p>Поскольку размер файлов, как правило, превышает количество элементов, которое может уместиться на одной экранной строке, для отображения содержимого файла может отводиться более одной экранной строки. Слева от каждой строки с содержимым файла указывается порядковый номер файлового элемента, значение которого указано первым в этой строке (элементы нумеруются от 1).</p> <p>Запуск нашей программы признан <i>ознакомительным</i> (и поэтому правильность решения не анализировалась), так как в ходе ее выполнения не было введено ни одного элемента исходных данных. При ознакомительном запуске раздел результатов не отображается, однако приводится <i>пример верного решения</i>, т. е. те числа, которые должны содержаться в результирующем файле при правильной обработке исходных файлов.</p> </p> <hr> <h3>Ввод части исходных данных</h3> <p>Добавим в программу фрагмент, позволяющий ввести имена исходных файлов и связать с этими файлами соответствующие файловые переменные. Поскольку мы собираемся работать с четырьмя файлами одного типа, удобно предусмотреть <i>массив</i> для хранения всех файловых переменных:</p> <blockquote> <code><pre> <b>uses</b> PT4; <b>var</b> i: integer; s: string; f: <b>array </b>[1..4] <b>of</b> <b>file</b> <b>of</b> integer; <b>begin</b> Task('File48'); <b>for</b> i := 1 <b>to</b> 3 <b>do</b> <b>begin</b> read(s); Assign(f[i], s); <b>end</b>; <b>end</b>. </pre></code> </blockquote> <p>Мы намеренно ограничились <i>тремя</i> итерациями цикла, оставив непрочитанным имя результирующего файла. Считывание имен файлов производится в одну и ту же переменную <code>s</code>, поскольку после связывания файла, имеющего имя <code>s</code>, с соответствующей файловой переменной (процедурой <code>Assign</code>) все остальные действия с данным файлом в нашей программе будут осуществляться с использованием файловой переменной, без обращения к имени файла.</p> <p>Запуск нового варианта программы уже не будет считаться ознакомительным, поскольку в программе выполняется ввод исходных данных. Так как имя результирующего файла осталось непрочитанным, этот вариант решения будет признан неверным и приведет к сообщению «<i>Введены не все требуемые исходные данные</i>»:</p> <blockquote> <img border="0" src="gif/file48-2.png"> </blockquote> <p>При этом на экране появится раздел результатов (кроме комментария он пока ничего не содержит), а также панель индикаторов. Первый из индикаторов (индикатор ввода) показывает количество введенных исходных данных. Обратите внимание на то, что второй индикатор (индикатор вывода) является неактивным: он выделяется серым цветом более светлого оттенка и не содержит текстового заголовка. Это объясняется тем, что индикатор вывода показывает количество результирующих данных, полученных задачником от программы, а в нашем случае программа не должна передавать задачнику никакие данные; вместо этого ей необходимо создать файл и заполнить его требуемыми значениями. Для заданий подобного типа (обычно это задания, связанные с обработкой файлов) индикатор вывода не используется. </p> <hr> <h3>Ввод всех исходных данных без создания требуемого файла</h3> <p>Изменим программу, заменив в заголовке цикла число <code>3</code> на <code>4</code>, и вновь запустим программу. Теперь все данные, необходимые для выполнения задания, введены в программу (это видно по индикатору ввода). Однако задание не выполнено, поскольку результирующий файл не создан. Поэтому решение опять признано ошибочным с диагностикой «<i>Результирующий файл не найден</i>»:</p> <blockquote> <img border="0" src="gif/file48-3.png"> </blockquote> <hr> <h3>Пример программы, приводящей к ошибке времени выполнения</h3> <p>Добавим в тело цикла после процедуры <code>Assign</code> вызов процедуры <code>Reset</code>, обеспечивающий открытие существующего файла:</p> <blockquote> <code><pre> <b>uses</b> PT4; <b>var</b> i: integer; s: string; f: <b>array </b>[1..4] <b>of</b> <b>file</b> <b>of</b> integer; <b>begin</b> Task('File48'); <b>for</b> i := 1 <b>to</b> 4 <b>do</b> <b>begin</b> read(s); Assign(f[i], s); Reset(f[i]); <b>end</b>; <b>end</b>. </pre></code> </blockquote> <p>Теперь запуск программы приведет к сообщению об ошибке «<i>Error System.IO.FileNotFoundException</i>»:</p> <blockquote> <img border="0" src="gif/file48-4.png"> </blockquote> <p>Сообщение, начинающееся со слова <i>Error</i>, означает, что при работе программы произошла <i>ошибка времени выполнения</i> (Runtime Error). После слова <i>Error</i> указывается имя этой ошибки (в данном случае <i>System.IO.FileNotFoundException</i>, то есть ошибка ввода-вывода, связанная с тем, что файл не найден) и краткое ее описание на английском языке.</p> <p>Сообщение об ошибке времени выполнения появится и в разделе «Список ошибок» окна <b>PascalABC.NET</b>:</p> <blockquote> <img border="0" src="gif/file48-5.png"> </blockquote> <hr> <h3>Создание пустого результирующего файла</h3> <p>Для того чтобы избежать ошибки времени выполнения, отсутствующий файл результатов следует открыть не процедурой <code>Reset</code>, а процедурой <code>Rewrite</code>, которая и обеспечит создание этого файла. Далее, после завершения работы с файлами, открытыми в программе, их необходимо закрыть процедурой <code>Close</code>. Добавим в программу соответствующие операторы:</p> <blockquote> <code><pre> <b>uses</b> PT4; <b>var</b> i: integer; s: string; f: <b>array </b>[1..4] <b>of file of</b> integer; <b>begin</b> Task('File48'); <b>for</b> i := 1 <b>to</b> 4 <b>do</b> <b>begin</b> read(s); Assign(f[i], s); <b>if</b> i < 4 <b>then</b> Reset(f[i]) <b>else</b> Rewrite(f[i]); <b>end</b>; { * } <b>for</b> i := 1 <b>to</b> 4 <b>do</b> Close(f[i]); <b>end</b>. </pre></code> </blockquote> <p>Комментарий <code>{ * }</code> расположен в том месте программы, в котором можно выполнять операции ввода-вывода для всех четырех файлов: они уже открыты процедурами <code>Reset</code> или <code>Rewrite</code> и еще не закрыты процедурой <code>Close</code>.</p> <p>Запуск этого варианта программы не приведет к ошибке времени выполнения; более того, результирующий файл будет создан. Однако созданный файл останется пустым, то есть не содержащим ни одного элемента. Поэтому при запуске программы на информационной панели появится сообщение «<i>Ошибочное решение</i>», а в строке, которая должна содержать элементы результирующего файла, появится текст <code>EOF:</code> (особое значение EOF для указателя текущей файловой позиции означает, что данный файл существует, но не содержит ни одного элемента):</p> <blockquote> <img border="0" src="gif/file48-6.png"> </blockquote> <hr> <h3>Пример программы, использующей неправильные типы для файловых данных</h3> <p>Во всех ранее рассмотренных вариантах программы мы не использовали операции ввода-вывода для файлов. Поэтому тип файлов не играл никакой роли: вместо типа <code><b>file of</b> integer</code> мы могли использовать любой другой файловый тип, например, <code><b>file of</b> real</code>, и результат выполнения программы был бы тем же самым.</p> <p>Тип файловых элементов становится принципиально важным, если в программе используются операции ввода-вывода для данного файла. Чтобы продемонстрировать это на примере нашей программы, внесем в нее следующие изменения: в описании массива <code>f</code> файловых переменных тип <code>integer</code> заменим на <code>real</code>, в раздел описаний добавим описание переменной <code>a</code> типа <code>real</code>, в раздел операторов (в позицию, помеченную комментарием <code>{ * }</code>) добавим следующий фрагмент:</p> <blockquote> <code><pre> <b>for</b> i := 1 <b>to</b> 3 <b>do</b> <b>begin</b> read(f[i], a); write(f[4], a); <b>end</b>; </pre></code> </blockquote> <p>Данный фрагмент обеспечивает считывание <i>одного</i> элемента для каждого из трех исходных файлов и запись этих элементов в результирующий файл (в требуемом порядке). Подчеркнем, что мы <i>неправильно</i> указали типы файлов; тем не менее, компиляция программы пройдет успешно, а после ее запуска не произойдет ошибок времени выполнения.</p> <p>Результат работы программы будет неожиданным:</p> <blockquote> <img border="0" src="gif/file48-7.png"> </blockquote> <p>Судя по экранной строке с содержимым результирующего файла, в него будут записаны не три, а <i>шесть элементов</i>, по два начальных элемента из каждого исходного файла. Объясняется это тем, что после связывания файлов с файловыми переменными типа <code><b>file of</b> real</code> элементами файлов стали считаться <i>вещественные числа</i> (занимающие в памяти по 8 байтов), тогда как «на самом деле», то есть по условию задания, элементами файлов являются целые числа (занимающие в памяти по 4 байта). Поэтому считывание из файла и последующая запись в файл одного «вещественного элемента» фактически приводит к считыванию и записи блока данных размером 8 байтов, содержащего <i>два</i> последовательных целочисленных элемента исходного файла.</p> <p>Итак, мы выяснили, что ошибки, связанные с несоответствием типов файлов, не выявляются при компиляции и не всегда приводят к ошибкам времени выполнения. Это следует иметь в виду, и при появлении «странных» результирующих данных начинать поиск ошибки с проверки типов файловых переменных.</p> <hr> <h3>Исправление ошибки, связанной с неверными типами файловых данных</h3> <p>Заменим в нашей программе все описания <code>real</code> на <code>integer</code>:</p> <blockquote> <code><pre> <b>uses</b> PT4; <b>var</b> i: integer; s: string; f: <b>array </b>[1..4] <b>of file of</b> integer; a: integer; <b>begin</b> Task('File48'); <b>for</b> i := 1 <b>to</b> 4 <b>do</b> <b>begin</b> read(s); Assign(f[i], s); <b>if</b> i < 4 <b>then</b> Reset(f[i]) <b>else</b> Rewrite(f[i]); <b>end</b>; <b>for</b> i := 1 <b>to</b> 3 <b>do</b> <b>begin</b> read(f[i], a); write(f[4], a); <b>end</b>; <b>for</b> i := 1 <b>to</b> 4 <b>do</b> Close(f[i]); <b>end</b>. </pre></code> </blockquote> <p>Мы получим все еще неверное, но вполне «понятное» решение: первые три элемента результирующего файла совпадают с контрольными (то есть «правильными»), а прочие элементы отсутствуют:</p> <blockquote> <img border="0" src="gif/file48-8.png"> </blockquote> <hr> <h3>Верное решение</h3> <p>Приведем, наконец, верное решение задания <code>File48</code>:</p> <blockquote> <code><pre> <b>uses</b> PT4; <b>var</b> i, a: integer; s: string; f: <b>array </b>[1..4] <b>of file of</b> integer; <b>begin</b> Task('File48'); <b>for</b> i := 1 <b>to</b> 4 <b>do</b> <b>begin</b> read(s); Assign(f[i], s); <b>if</b> i < 4 <b>then</b> Reset(f[i]) <b>else</b> Rewrite(f[i]); <b>end</b>; <b>while</b> <b>not</b> Eof(f[1]) <b>do</b> <b>for</b> i := 1 <b>to</b> 3 <b>do</b> <b>begin</b> read(f[i], a); write(f[4], a); <b>end</b>; <b>for</b> i := 1 <b>to</b> 4 <b>do</b> Close(f[i]); <b>end</b>. </pre></code> </blockquote> <p>От предыдущего варианта данное решение отличается добавлением заголовка цикла <code><b>while not</b> Eof(f[1]) <b>do</b></code>, который обеспечивает считывание всех элементов из исходных файлов (напомним, что по условию задания все исходные файлы имеют <i>одинаковый размер</i>) и запись их в результирующий файл в нужном порядке. После запуска этого варианта мы получим сообщение «<i>Верное решение. Тест номер 1 (из 5)</i>», а после пяти подобных запусков — сообщение «<i>Задание выполнено!</i>»:</p> <blockquote> <img border="0" src="gif/file48-9.png"> </blockquote> <hr> <h3>Просмотр результатов выполнения задания</h3> <p>Щелкнув мышью на метке «Результаты (F2)», расположенной в правом верхнем углу окна задачника, или нажав клавишу <b>F2</b>, мы можем вывести на экран <i>окно результатов</i>, в котором будет перечислены все наши попытки решения задачи:</p> <blockquote> <code><pre> File48 a08/09 12:43 Ознакомительный запуск. File48 a08/09 12:50 Введены не все требуемые исходные данные. File48 a08/09 12:52 Результирующий файл не найден. File48 a08/09 12:53 Error System.IO.FileNotFoundException. File48 a08/09 12:57 Ошибочное решение.--3 File48 a08/09 13:06 Задание выполнено! </pre></code> </blockquote> <p>Для закрытия окна результатов достаточно нажать клавишу <b>Esc</b>. Окно результатов можно отобразить на экране и после закрытия окна задачника и возврата в среду PascalABC.NET. Для этого надо использовать команду меню «Модули | Просмотреть результаты», кнопку <img border="0" src="gif/Results.gif" width="16" height="17"> или клавиатурную комбинацию <b>Shift+Ctrl+R</b>. </p> </body> </html>