Работа с файлами

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

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

Создание (описание) файловой переменной;

Связывание этой переменной с конкретным файлом на диске или с устройством ввода-вывода (экран, клавиатура, принтер и т.п.);

Открытие файла для записи либо чтения;

Действия с файлом: чтение либо запись;

Закрытие файла.

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

CON - консоль (экран-клавиатура), то есть по записи в это устройство мы будем получать информацию на экран, при чтении информации из этого устройства, будем читать данные с клавиатуры.

PRN - принтер. При записи в это устройство вы получите информацию на принтер.

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

Типы файловых переменных

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

Text - текстовый файл. Из переменной такого типа мы сможем читать строки и символы.

File of _любой_тип_ - так называемые "типизированные" файлы, то есть файлы, имеющие тип. Этот тип определяет, какого рода информация содержится в файле и задается в переметре _любой_тип_. К примеру, если мы напишем так:

F: File of Integer;

То Паскаль будет считать, что файл F содержит числа типа Integer; Соответсвенно, читать из такого файла мы сможем только переменные типа Integer, ровно как и писать. Напишем так :

type
A = record

I,J: Integer;

end;

var

F: File of A;

File - нетипизированный файл. Когда мы указываем в качестве типа файла просто File, то есть без типа:

F: File;

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

Связывание переменной с файлом

Самый универсальный шаг. Выполняется одной и той же процедурой для всех типов файлов, а именно процедурой Assign:

Assign(_переменная_файлового_типа_, 'путь к файлу');

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

var

T: Text;

F1: File of Byte;

F2: File;

begin

Assign(T, '1.txt');

Assign(F1, 'C:\Programm\Tp\2.txt');

Assign(F2, 'F:\usr\bin\apache\conf\httpd~1.con');

..........

Открытие файла

Открытие файла - это уже более усложненный процесс, нежели связывание с ним переменной. Здесь учитывается, зачем открывается файл - для записи или чтения, а также в зависимости от типа файла процедуры выполняют различные действия.

Тем не менее этот процесс не сложен и заключается в использовании одной из трех имеющихся процедур:

Reset(_любая_файловая_переменная_);
Открыват файл на чтение. В качестве параметра - файловая переменная любого из перечисленных выше типов. Это может быть текстовый, типизированный либо не типизированный файл. В случае с текстовым файлом, он открывается только на чтение. В случае с типизированным и нетипизированным файлом - он открывается на чтение и запись.

Append(T: Text);
Эта процедура открывает текстовый файл (только текстовый!) на запись. Выше я сказал, что Reset при задании параметра типа Text не позволит писать в него данные, открыв файл лишь для чтения. То есть если вы используете текстовый файл и хотите производить в него запись, нужнo использовать Append. Если чтение - Reset. В остальных случаях дело обходиться одной процедурой Reset.
Также обратите внимание, что если вы до этого уже открыли файл на чтение, вам не нужно закрывать его и открывать снова на запись. В этом случае файл закрывается сам и открывается заново. При записи данных в файл при открытии его с помощью этой процедуры они записываются в конец файла.

ReWrite(F) - создает новый файл либо перезаписывает существующий. Будьте осторожны, если не хотите случайно удалить нужный файл. Напомню, файл, открытый с помощью этой процедуры будет полностью перезаписан.

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

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

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

Оформляются ключи следующим образом: в скобках комментариев "{}" первым символом после открывающей скобки "{" ставиться знак доллара "$", после чего указывается имя ключа и его значение. Нас интесует ключ, который выключает вывод ошибок ввода-вывода, называется он "I". Выглядит все это следующим образом:

{$I+} - включение вывода ошибок
{$I-} - выключение вывода ошибок

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

Связываем переменную с файлом;

Выключаем вывод ошибок на экран - {$I-}

Открываем файл необходимой нам процедурой;

Включаем вывод ошибок {$I+} - пусть будет для дальнейшего отслеживания таковых;

Проверяем, если IOResult возвращает нуль, то все было путем и файл открыт. Иначе выводим ошибку.

Вот пример такой программы:

program qwer;

var

b:text;

begin

assign (b,'c:\turbo\proba.txt');

{$I-} отключает контроль ошибок

reset (b);

{$I+} включает контроль ошибок.

if IOResult <> 0 then write(' файл не существует ')

else

write(' есть такой файл ') end.

End .

Закрытие файла

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

Запись и чтение файлов, часть I.

Чтение файлов. Чтение файлов производится с помощью отлично известных нам процедур Read и Readln. Они используются также, как и при чтении информации с клавиатуры. Отличие лишь в том, что перед переменной, в которую помещается считанное значение, указывается переменная файлового типа (дескриптор файла):

Read(F, C);
Здесь F - дескриптор файла, C - переменная (Char, String - для текстовых, любого типа - для типизированных файлов).

Также сразу хочу упомянуть о одной, пожалуй самой главной функции при чтении файлов. Это функция поверки на конец файла - Eof(F): Boolean;. В качестве параметра - файловая переменная любого типа. Функция возвращает TRUE если достигнут конец файла и FALSE иначе.

Запись в файлы. Запись в файлы производиться точно так же, как и запись на экран - с помощью процедур Write и Writeln. Как и в случае с чтением, перед записываемой в файл переменной указывается тескриптор файла:

Write(F, S);

Здесь F - дескриптор, S - переменная.

При этом, естественно, переменная должна соответствовать типу файла. Примера ради давайте составим еще одну небольшую программку, которая покажет работу с файлами. На сей раз уже используем типизированные файлы, а имеено состоящие из чисел. Итак, мы имеем файл, в котором содержаться числа типа Integer. Давайте отсортируем эти числа в файле по возрастанию.

План дейтсвий:

Отрываем типизированный файл из Integer; (проверяем на ошибку и т.п.)

Читаем все числа в массив (считываем, пока не конец файла)

Сортируем массив по возрастанию;

Записываем отсортированный массив обратно в файл.

Получается такая программа:

Program Sorting;

uses Crt;

var

F: File of Integer;

I, J, M: Word;

Mas: Array[1..500] of Integer;

S: String;

begin

ClrScr;

Write('Enter filename: ');

Readln(S);

{ открываем файл }

Assign(F, S);

{$I-}

Reset(F);

{$I+}

if IOResult <> 0 then

begin

Write('Error when open file!');

Halt;

end;

{ пока не конец файла, читаем массив }

While (not Eof(F)) do

begin

Inc(M);

Read(F, Mas[M]);

Write(Mas[M], ' ');

end;

{ сортируем массив по возрастанию }

For I := 1 to M do

For j := 1 to M do

if Mas[I] < Mas[J] then

begin

inc(mas[j], mas[i]);

mas[i] := mas[j]-mas[i];

dec(mas[j], mas[i]);

end;

Writeln; Writeln('=============================================');

{ перезаписываем файл }

ReWrite(F);

For I := 1 to 100 do

begin

Write(Mas[I], ' ');

Write(F, Mas[i]);

end;

Writeln; Write('Elements in file: ', M);

Close(F);

Readln;

end.

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

Assign (FileName, DosFullName) - связывает файловую переменную FileName с конкретным файлом DOS, полное имя которого DosFullName;
Reset (FileName) - открыть файл на чтение, установить указатель на первый элемент в файле; если файла не существует, то возвращается ошибка;
Rewrite (FileName) - открыть файл на запись, установить указатель на первый элемент в файле; если файла не существует - открыть новый файл;
Close (FileName) - завершает действия с файлом и разрывает связь с файловой переменной FileName;
Read (FileName, список) - чтение значений начиная с текущей позиции указателя в список ввода; после каждого чтения указатель смещается на следующую позицию, при достижении конца файла возвращает ошибку;
Write (FileName, список) - запись списка выражений в файл; продвижение указателя на количество элементов списка;
Seek (FileName, Number) - явная установка указателя на элемент файла с номером Number;
Truncate (FileName) - отсечение от файла его хвостовой части, начинающейся с текущей позиции указателя включительно;
FileSize (FileName) - возвращает число элементов файла;
FilePos (FileName) - возвращает номер элемента, на который установлен текущий указатель;
EoF (FileName) - возвращает логическое значение True или False, говрящее о достижении конца файла.