Опубликован: 25.06.2014 | Уровень: для всех | Доступ: платный | ВУЗ: Учебный центр "ANIT Texno Inform"
Лекция 21:

Файлы

< Лекция 20 || Лекция 21: 1234 || Лекция 22 >
Аннотация: На этой лекции мы изучим работу с файлами: текстовыми, типизированными и нетипизированными. Весь материал подкреплен подробными примерами.

Цель лекции

Научится работать с различными видами файлов.

Файлы

Файл - это область внешней памяти ПК, которая имеет имя.

То есть, файл - это часть ПЗУ - Постоянного Запоминающего Устройства, которым может быть жесткий диск, дискета, флэш-карта, CD или DVD. В операционных системах существуют различные файловые структуры, или, как еще говорят, таблицы размещения файлов. Например, в Windows это может быть FAT32 или NTFS. В этих таблицах имена файлов соотносятся с реальным адресом на диске. На уровне машинных кодов, реальный адрес файла представляет собой целое число - номер байта, с которого начинается файл. Также в таблице содержится общее количество байтов, занятых файлом. Но при программировании на языках высокого уровня, таких, как Объектный Паскаль, мы можем пользоваться символическими именами файлов, которые автоматически преобразуются операционной системой в реальные адреса и размеры этих файлов.

Файлы бывают трех типов:

  1. Текстовые файлы. Это файлы, предназначенные для работы с текстом.
  2. Типизированные файлы. Такие файлы могут хранить массив записей какого-то одного, указанного типа. Это может быть очень удобно для создания файла с данными.
  3. Нетипизированные файлы. Это файлы для побайтовой работы с данными любого типа. Могут использоваться для копирования или переноса файлов, тем более что отсутствие типа делает такие файлы более универсальными, совместимыми с любым существующим типом. Кроме того, у нетипизированных файлов обмен данными между памятью и диском более скоростной, что важно при обработке файлов большого размера.

Чтобы открыть доступ к файлу, требуется создать файловую переменную одним из трех способов:

var
   f1: TextFile;  //текстовый файл
   f2: File of <тип>;  //типизированный файл
   f3: File;  //нетипизированный файл
    

Типизированный файл может работать с любыми типами Объектного Паскаля, кроме файлов. Это может быть целое или вещественное число, символ, строка или даже пользовательский тип данных, например, запись (о записях - в следующей лекции). Например, объявить типизированный файл, работающий с символами, можно так:

var
   MyF: File of Char;  //типизированный символьный файл
    

Однако для работы с файлами мало объявить переменную файлового типа, нужно еще эту переменную "привязать" к конкретному файлу. Делается это с помощью процедуры AssignFile, в которую передается два параметра - имя файловой переменной, к которой "привязывается" файл, и имя существующего файла, с которым мы хотим работать. Если имя файла указано без адреса, то процедура подразумевает, что файл находится в текущей папке. Если файла нет, программа вызовет ошибку, поэтому рекомендуется всегда перед связыванием файловой переменной с файлом вначале проверить - существует ли файл? Делается это с помощью функции FileExists, с которой нам уже доводилось работать, и которая возвращает True, если указанный файл существует, и False в противном случае. Вот пример связывания файловой переменной с файлом:

var
   f1: TextFile;  //текстовый файл
begin
   if FileExists('c:\01\myfile.txt') then begin 
      AssignFile(f1, 'c:\01\myfile.txt'); //связали файловую переменную с файлом 
      ... //дальнейшая работа с файлом 
   end; //if
    

После того, как мы связали файловую переменную с файлом, мы можем обращаться к ней, как к файлу. Мы можем открыть её, считать или записать информацию, закрыть. А после работы с файлом его обязательно нужно закрыть! Делается это процедурой CloseFile, в которую передается всего один параметр - имя файловой переменной, например:

CloseFile(f1);  //закрыли файл, с которым была связана файловая переменная f1
    

Во время работы с файлом может возникнуть исключительная ситуация. Внимание! Такой термин мы встречаем впервые, и он очень важен для понимания. Что такое исключительная ситуация? Это любая ошибка программы, которая может произойти во время работы. Например, вы открыли какой-то сетевой файл и начали работу с ним. А другой пользователь в это время взял, да удалил этот файл. Или вы пытаетесь работать с файлом, который содержит вирус. Как только вы обратились к нему, ваш антивирус вмешивается, и удаляет файл, или переносит его в карантин. Или же ваш файл "битый" - содержит ошибку, и не может прочитаться.

При попытке чтения из несуществующего файла, или записи в него, или при работе с "битым" файлом произойдет ошибка и возникнет исключительная ситуация. Если вы не обработаете эту ошибку, то ваша программа, скорее всего, намертво повиснет. Вам придется вызывать Диспетчер задач Windows, и снимать задачу - принудительно закрывать вашу программу. Поэтому в любой ситуации, когда имеется риск возникновения исключительной ситуации, программист ВСЕГДА должен ее обработать. Для этого существует блок try-finally-end:

try 
   //блок кода, в котором может произойти ошибка 
finally 
   //код, который должен выполниться в любом случае, например, код закрытия файла 
end;
    

Между служебными словами try-finally вы вписываете потенциально опасный код. То есть, код, который может вызвать ошибку. А между finally-end указываете тот код, который должен быть выполнен в любом случае, даже при возникновении ошибки. Вот более правильный пример того, как нужно связывать файл с переменной:

var
   f1: TextFile;  //текстовый файл
begin
   try
      AssignFile(f1, 'c:\01\myfile.txt'); //связали файловую переменную с файлом 
      …;   //дальнейшая работа с файлом - чтение/запись
   finally
      CloseFile(f1);  //по окончании закрываем файл
   end;  //try
    

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

Есть и другой способ обработки исключительных ситуаций - блок try-except-end:

try 
   //блок кода, в котором может произойти ошибка 
except 
   //код, который выполнится в том случае, если в блоке между try-except произошла ошибка
end;
    

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

var
   f1: TextFile;  //текстовый файл
begin
   try
      AssignFile(f1, 'c:\01\myfile.txt'); //связали файловую переменную с файлом 
      …;   //дальнейшая работа с файлом - чтение/запись
      CloseFile(f1);  //по окончании закрываем файл
   except
      ShowMessage('Внимание! Произошла ошибка открытия файла.');
   end;  //try
    

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

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

Reset(f1);
    

При этом указатель устанавливается в начало файла, в нулевую позицию.

Если нам нужно создать новый файл, или перезаписать существующий, используется процедура Rewrite:

Rewrite(f2);
    

Если файл уже существовал, он будет перезаписан без каких либо предупреждений. Если же нам нужно открыть для записи существующий файл, не удаляя содержащейся в нем информации, воспользуемся процедурой Append:

Append(f1);
    

Файл будет открыт для записи, а указатель переместится в конец файла. Однако, процедура Append применима только к текстовым файлам, то есть к переменным типа TextFile.

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

if Eof(f1) then ShowMessage('Достигнут конец файла.');
    

Есть еще один способ проверки существования файла, и вообще обработки ошибок ввода-вывода в файл. Это - функция IOResult, которая возвращает ноль при отсутствии ошибок ввода-вывода, и номер ошибки в противном случае. Но использовать эту функцию просто так не получится. Lazarus автоматически обрабатывает ошибки ввода-вывода. Прежде чем использовать IOResult, нужно дать процессору команду отключить автоматическую обработку этих ошибок. Для этого существует директива процессора {$I-}. Затем мы выполняем опасный участок кода, где может произойти ошибка, после чего снова включаем автоконтроль операций ввода-вывода директивой {$I+}. Затем вызываем IOResult. Если операция произошла успешно, то функция вернет ноль. Пример:

var
   f1: TextFile;
begin
   AssignFile(f1, 'MyText.txt');  //связали файл с переменной
   {$I-}  //отключили автоконтроль ввода-вывода
   Reset(f1);  //пытаемся открыть файл для чтения
   {$I+}  //снова включили автоконтроль ввода-вывода
   if IOResult <> 0 then
      ShowMessage('Внимание! Произошла ошибка открытия файла.');
    
< Лекция 20 || Лекция 21: 1234 || Лекция 22 >
Инга Готфрид
Инга Готфрид
Александр Скрябнев
Александр Скрябнев

Через WMI, или используя утилиту wmic? А может есть еще какие более простые пути...