Покажем как можно быстро преодолеть все сложности работы с файлами…

Покажем, как можно быстро преодолеть все сложности работы с файлами и сделать при этом как можно меньше ошибок.
Как уже видно из примера, приведенного в конце предыдущего раздела, для организации ввода данных из текстового файла наличие файловой переменной типа text в программе вовсе не обязательно. Более того, перенаправление стандартного потока ввода input и потока вывода output в файлы является и более удобным при программировании и избавляет от ряда ошибок. Как это можно сделать видно из приведенного выше примера (см. также лекцию 2). После подобного перенаправления ввод данных из файла осуществляется с помощью обычных процедур read и readln, а вывод — с помощью write и writeln без указания в качестве первого параметра имени какой-либо файловой переменной. Такой подход избавляет от типичной ошибки при работе с текстовыми файлами, которая заключается в том, что в некоторых обращениях к процедурам ввода или вывода имя файловой переменной оказывается пропущенным. Это не нарушает работу программы в целом, так как часть информации может быть записана в файл, а часть — выведена на экран. Но так как проверке подлежит лишь создаваемый программой файл, то скорее всего оценить такую программу на олимпиаде будет невозможно. Вторая типичная ошибка при работе с файлом, открытым на запись — отсутствие в конце программы команды, закрывающей файл. В таком случае, создаваемый программой выходной файл скорее всего окажется пустым. Дело в том, что реальная запись данных на жесткий диск происходит или при выполнении уже упомянутой команды close или, если количество выводимой информации велико, в момент переполнения буфера оперативной памяти, предназначенного для ускорения работы с файлами. Но и от этой ошибки работа со стандартным потоком вывода спасает. Дело в том, что файл output закрывается при окончании работы программы автоматически, вне зависимости от наличия или отсутствия команды close(output).
Рассмотрим теперь полезные приемы программирования ввода данных различных типов. Начнем с описания считывания из текстового файла или консоли (клавиатуры), которая с точки зрения программы также является текстовым файлом, числовых данных. В условии задачи ввод большого количества чисел может быть задан двумя способами. В первом способе сначала предлагается ввести количество чисел, а уж затем сами эти числа. В данном случае при программировании сложности не возникают. Во втором же случае количество чисел приходится определять в процессе их считывания. Пусть, например, для каждой строки входного файла требуется найти среднее арифметическое для чисел, расположенных в ней, количество чисел в каждой из строк и количество строк при этом неизвестно. Наиболее простым и правильным будет следующее решение такой задачи:
while not seekeof do
begin
n:=0;
s:=0;
while not seekeoln do
begin
read(a);
s:=s+a;
n:=n+1
end;
{readln;}
if n>0 then writeln(s/n:0:2) else writeln
end;

Заметим, что обычно применяемые в таких случаях функции eof и eoln заменены на seekeof и seekeoln соответственно. Имя файловой переменной при этом опускается, что опять же возможно для стандартного потока ввода, даже после перенаправления его в файл. Только при показанном способе ввода чисел не возникают ошибки в работе подобной программы, связанные с наличием пробелов в конце строк и пустых строк в конце файла, так как для корректного использования функции eof требуется, чтобы признак конца файла стоял непосредственно после последнего числа в файле. То же требование относится к признаку конца строки при использовании функции eoln. Несмотря на то, что числа расположены в различных строках файла, процедуру readln при вводе именно чисел можно не использовать (в приведенном примере она взята в комментарий, снятие которого не изменит работу программы). Отметим, что техническую проблему, связанную с обработкой заранее неизвестного количества чисел в строке или в файле в целом, разрешить на языке программирования Си несколько сложнее.
Наоборот, если во входном файле находится текст, размер которого неизвестен, то поступать следует несколько по другому. Использование seekeoln может привести к ошибке, так как в тексте пробел уже является значимым символом. С другой стороны, служебные символы, обозначающие конец строки в файле и перевод на новую строку (их коды 13 и 10), не могут считаться частью текста и не должны анализироваться алгоритмом его обработки. Поэтому, если известно, что длина каждой строки текстового файла не превосходит 255 символов, то удобнее всего считывание производить с использованием переменной типа string:
while not eof do
begin
readln(S);
if s» then {обработать строку S}
end;

В этом примере использование readln, а не read является уже принципиальным. Если же ограничения на количество символов в одной строке нет, то считывание следует производить посимвольно. Причем на Всероссийской или международной олимпиаде отсутствие такого ограничения означает, что при тестировании программы действительно будут тесты, содержащие очень длинные строки, а на школьной или районной олимпиаде, — что скорее всего такое ограничение просто забыли включить в текст условия, а все тесты будут состоять все-таки из коротких строк. Пример посимвольного считывания текста из файла:
while not eof do
begin
n:=0;
s:=0;
while not eoln do
begin
read(с);
{запись символа с в массив или его обработка}
n:=n+1
end;
readln;{!!!}
if n>0 then {обработка строки} else {строка пустая}
end;

Именно использование оператора readln позволяет и в данном случае автоматически исключить из рассмотрения символы перевода строки.
Последний вариант считывания данных относится к случаю смешанной информации, то есть в файле присутствуют как числа, так и символы или последовательности символов. Формат такого файла обычно определен заранее, поэтому считывание можно организовать сразу в переменные соответствующих типов. Наоборот, считывание информации в одну строковую переменную, а затем выделение из нее отдельных элементов и преобразование строкового представления данных в числовое, делает программу более громоздкой и зачастую требует отладки. Пусть, например, в каждой строке файла записана фамилия человека, затем через пробел его год рождения и, наконец, опять же через пробел — его пол, обозначенный одной буквой. Приведем фрагмент программы, считывающий данные описанного формата из файла сразу в переменные соответствующих типов:
while not seekeof do
begin
read(c);
S:=»;
{формируем строку с фамилией}
while c’ ‘ do
begin
S:=S+c;
read(с)
end;
read(n);{считываем год рождения}
readln(c,c);{считываем пол}
{обработка считанной информации}
end;

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

Если же результат работы программы представляет из себя произвольное вещественное число, то формат его вывода обычно оговорен в условии задачи. Так, если требуется получить в дробной части три цифры, то печать можно производить по формату x:0:3.

Директивы компилятора
Инициализация данных и создание динамических переменных
Подсчет времени работы программы

Понравилась статья? Поделиться с друзьями: