344 lines
14 KiB
HTML
344 lines
14 KiB
HTML
<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>
|