Урок 10.1. Описание файлов

10. Файлы
10.1. Описание файлов
10.2. Открытие и закрытие файлов

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

Файл - это такой же объект программы, как и любые другие, но разница заключается в том, что данные файла находятся не в оперативной памяти, а вне ее, и, таким образом, файл является долговременным "хранилищем" данных вне программы. Отключение питания компьютера не приводит к разрушению данных файла, если в момент отключения над ним не производились операции. Си допускает файлы двух разновидностей – текстовые и двоичные (бинарные).

Текстовый файл состоит из последовательности символов, разбитых на строки. Для стандартного деления на строки используется символ “новая строка ”, который в файле представляется двумя символами '\n' (новая строка) и '\r' (возврат каретки). Строки в файле представляют собой последовательности непробельных символов. Кроме символа “пробел”, ‘\n’, и ‘\r’ пробельными символами являются символы ‘\t’, ‘\v’, ‘\f’ – горизонтальная и вертикальная табуляция, перевод страницы.

В текстовом файле хранятся только символы, т.е. если в файле записано 123, то это не целое число 123, занимающее 1 или 4 байта, а три символа '1','2','3', занимающие 3 байта. Хотя при чтении из файла эта последовательность может быть преобразована в число типа double или int, char, long.

Двоичный (бинарный) файл состоит из последовательности байтов, между которыми нет никаких разделителей. Если в двоичном файле попадается байт с кодом управляющего символа новой строки, то он не имеет никакого специального назначения и рассматривается в файле точно так же, как и другие байты файла. Если в бинарный файл записать отрицательное целое число -12345, то оно запишется в файл в дополнительном коде, в котором представляются отрицательные числа в памяти компьютера, и будет занимать 4 байта. При чтении это число нет необходимости преобразовывать, как в случае текстового файла. Если же записать в бинарный файл последовательность символов -12345, то она будет занимать 6 байтов.

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

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

Для обработки файлов Си предлагает широкий набор встроенных функций, основные из которых будут рассмотрены далее. Для более полного ознакомления со средствами обработки файлов необходимо обратиться к пользовательской документации по системе.

10.1. Описание файлов

Программа получает доступ к файлу через указатель на структуру типа FILE, определенную в файле stdio.h. Тип FILE определяется оператором typedef как тип структурного шаблона. В пользовательской программе создается указатель на такую структуру и, таким образом, описание файла сводится для программиста к описанию указателя типа FILE и вся дальнейшая работа с файлом происходит через этот указатель. Примеры структурных шаблонов типа файл:

//для BorlandC
typedef struct  {
  int             level;        /* fill/empty level of buffer */
  unsigned        flags;        /* File status flags          */
  char            fd;           /* File descriptor            */
  unsigned char   hold;         /* Ungetc char if no buffer   */
  int             bsize;        /* Buffer size                */
  unsigned char   _FAR *buffer; /* Data transfer buffer       */
  unsigned char   _FAR *curp;   /* Current active pointer     */
  unsigned        istemp;       /* Temporary file indicator   */
  short           token;        /* Used for validity checking */
} FILE;                         /* This is the FILE object    */
 
//для MS VisualC
struct _iobuf {
        char *_ptr;
        int   _cnt;
        char *_base;
        int   _flag;
        int   _file;
        int   _charbuf;
        int   _bufsiz;
        char *_tmpfname;
        };
typedef struct _iobuf FILE;

Оператор описания файлов имеет следующую общую форму записи:

FILE *<имя1>,*<имя2>,...,*<имяN>;

из которой видно, что использованные имена являются указателями на файловый тип. Имена, заданные в операторе описания файлов, будем называть указателями файлов. Например, оператор FILE *fp1,*fp2; приводит к выделению памяти под два указателя файла – fp1 и fp2, которые будут использованы встроенными функциями обработки файлов.

10.2. Открытие и закрытие файлов

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

<указатель файла> = fopen(<имя файла>,<режим открытия>);

в котором
<указатель файла>           – указатель на тип FILE;
<имя файла>                       – строка символов, определяющая имя файла,
который необходимо открыть, либо указатель на строку, содержащую имя файла;
<режим открытия>            – строка символов либо указатель на строку,
определяющую, как используется файл (см. таблицу)

Таблица. Режимы открытия файла

Режимы Описание режима Позиция ввода-вывода
r Открытие файла только для чтения. Файл должен существовать. Начало файла
w Создание файла для записи. Если файл с указанным именем существовал, то его содержимое теряется. Начало файла
a Открытие файла для добавления в конец файла. Если файл с указанным именем не существовал, то он создается. Конец файла
r+ Открытие существующего файла для обновления (чтение и запись). Файл должен существовать. Конец файла
w+ Создание файла для обновления. Если файл с указанным именем существовал, то его содержимое теряется. Начало файла
a+ Открыть файл для чтения и добавления данных. Все операции записи выполняются в конец файла, защищая предыдущее содержания файла от случайного изменения. Вы можете изменить позицию (FSEEK, перемотка назад) внутреннего указателя на любое место файла только для чтения, операции записи будет перемещать указатель в конец файла, и только после этого дописывать новую информацию. Файл создается, если он не существует. Конец файла

Дополнительно к каждой строке <режим открытия> можно добавить символ t или b (по умолчанию t); t указывает, что файл открыт в текстовом режиме, а b указывает на то, что открывается двоичный файл, при этом символы новой строки и ввода подавляются. Возможны также и другие режимы открытия файла, например, "wt+,ccs=UNICODE" – открытие файла на запись в кодировке UNICODE.

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

 

Дескриптор файла является индексом в массиве операционной системы, называемом таблицей открытых файлов. Каждый элемент массива содержит блок управления файлом (FCB – File Control Block), который используется операционной системой для доступа к конкретному файлу. Для обращения к стандартному вводу, стандартному выводу и стандартному потоку ошибок следует воспользоваться указателями файлов  stdin, stdout и stderr соответственно.

Рассмотрим примеры. Допустим, исходные данные для программы расположены в файле с именем data.txt. Открыть этот файл для чтения можно следующим образом:

FILE *in;
in = fopen("data.txt","r");

После выполнения функции fopen() переменная in будет указывать на структуру, отражающую информацию о файле data.txt, и все действия с ним будут осуществляться посредством этого указателя, а не по имени файла. На рисунке 10.1 проиллюстрирована связь между указателем на FILE, структурой типа FILE и FCB в памяти компьютера.

Ris10.1File_FCB

Рис. 10.1. Связь между указателем на файл, структурой типа FILE и FCB

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

FILE *out;
if((out = fopen("outfile.txt","w"))==NULL)
     printf("Файл не может быть создан");

Заметим, что если в функции в качестве аргумента используется "w" для уже существующего файла, то старая версия его уничтожается, и информация существующего файла будет потеряна. Кроме того, обратим внимание на строку, задающую имя файла. Если в этой строке содержится только имя файла, как это имеет место в рассмотренном примере, то файл создается в текущем каталоге. В этой строке может быть указан полный путь, и тогда файл будет создан на определенном диске и в определенном каталоге:

FILE *out;
if((out = fopen("D:\\COURSE\\outfile.txt","w"))==NULL)
     printf("Файл не может быть создан");
 
//Имя файла в функции fopen() можно задать указателем на строку, 
//например, следующим образом:
 
//Открытие файлов
int i;
FILE *f[3]; // Массив указателей открываемых файлов 
char *file_name[] = // Массив указателей на имена 
                    // открываемых файлов 
	{"d:\\outfile1.txt",
	 "d:\\outfile2.txt",
	 "d:\\outfile3.txt"
	};
for(i=0;i<3;i++) {
 if((f[i] = fopen(file_name[i],"w"))==NULL)
 printf("Файл %s не может быть создан\n", file_name[i]);
}

 

Пример иллюстрирует открытие в цикле трех файлов. В результате откроются файлы с указателями файлов f[0], f[1], f[2]. Если какие-либо из этих файлов не могут быть открыты, будут напечатаны имена неоткрытых файлов.

 

Для закрытия файла используется функция fclose(), обращение к которой имеет вид:

fclose(<указатель_файла>);

Для контроля успешного закрытия файла желательно также анализировать возвращаемое значение функции fclose(). Функция возвращает значение 0, если файл закрыт успешно, и 1(EOF) в противном случае:

if(fclose(fsio)==EOF) printf("\n Файл не закрыт.");
 else printf("\n Файл закрыт.");

Не закрытые программой файлы операционная система сама закрывает по завершению программы. При этом, в случае буферизованного вывода, часть информации может не попасть в файл, а остаться в системном буфере. Операционная система использует буфер для оптимизации чтения-записи данных в файл. Например, если вы хотите прочитать или записать в файл 1000 целых чисел, это не означает, что система будет 1000 раз записывать или читать числа, образно говоря, не будет 1000 раз “дергать” диск. Данные будут перенесены в буфер c запасом для возможного последующего чтения, либо будут накапливаться в буфере для записи. Запись будет производиться, когда будет заполнен буфер, когда будет закрыт или сброшен поток (буфер), когда программа завершится нормально без закрытия потока. Поэтому критические важные данные можно принудительно переместить из буфера в файл при помощи функции fflush(). В случае чтения fflush() очищает буфер.

рассказать друзьям и получить подарок

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Translate Переводчик

Подписка на новости

SmartResponder.ru
Ваш e-mail: *
Ваше имя: *

Хостинг для Wordpress сайтов