Шаг 69.
Работа с файлами. Функции высокоуровневого ввода/вывода

    На этом шаге мы рассмотрим правила и функции работы с файлами "на высоком уровне".

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

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

    В этой функции указатель на файл должен быть описан так:

     FILE *fp; 

где тип FILE фактически является типом int (см. файл заголовков stdio.h). Возможные режимы доступа перечислены в таблице 1:

Таблица 1. Режимы доступа к файлам для функции fopen()
Строка режима
Описание
"r"
Открывает файл только для чтения. Модификация файла не разрешена.
"w"
Создает новый файл только для записи. Перезаписывает любой существующий файл с тем же именем. Чтение информации из файла не разрешено.
"a"
Открывает файл в режиме "только для записи" с добавлением новой информации в конец файла. Если файл не существует, он создается, а любой существующий файл с таким же именем перезаписывается. Чтение информации из файла не разрешено.
"r+"
Открывает существующий файл для чтения и записи.
"w+"
Создает новый файл для чтения и записи. Перезаписывает любой существующий файл с тем же именем.
"a+"
Открывает файл в режиме чтения и записи для добавления новой информации в конец файла. Если файл не существует, он создается, и любой существующий файл с тем же именем перезаписывается.

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

    Функция

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

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

    Для чтения информации из уже открытого файла или записи в него существует несколько возможностей. Рассмотрим пока самые простые - функции getc() и putc(). Функция

     getc (<указатель на файл>); 

возвращает очередной символ из файла с заданным указателем. Если уже достигнут конец файла, то функция возвращает значение EOF. Функция

     putc (<переменная>, <указатель на файл>); 
помещает значение переменной в файл с заданным указателем.

    С началом работы любой программы автоматически открываются три файла:

    Соответствующие ссылки на файлы называются stdin, stdout и stderr. По умолчанию все они связаны с терминалом, однако stdin и stdout можно связать с файлами и межпрограммными каналами. Ссылки на stdin, stdout и stderr имеются в файле стандартных заголовков stdio.h.

    Приведем несколько примеров, иллюстрирующих использование рассмотренных функций.


    Пример 1. Имитация команды type операционной системы MS DOS.
#include <iostream.h>
#include <stdio.h>
void main ()
{
   FILE *fp; /* Указатель на файл. */
   char ch;
   /* --------------------------------- */
   if ((fp = fopen ("c69_1.cpp","r")) != NULL)
   {  /* Открываем файл "c69_1.cpp" для чтения, одновременно */
      /* проверяя, существует ли он. Указатель fp ссыла- */
      /* ется на файл "c69_1.cpp". */
      while ((ch = getc (fp)) != EOF)
        /* Получаем символ из файла и проверяем, не */
        /* является ли этот символ концом файла. */
        putc (ch,stdout); /* Выводим этот символ. */
      fclose (fp); /* Закрываем файл. */
}
   else cout << "Файл \"f1.cpp\" отсутствует.\n";
}
Текст этой программы можно взять здесь.


    Пример 2. Имитация команды type операционной системы MS DOS (имя файла задается как аргумент командной строки).
#include <iostream.h>
#include <stdio.h>
void main (int argc,char *argv[])
{
   FILE *fp; /* Указатель на файл. */
   char ch;
   /* --------------------------------- */
   if  (argc<2)
         cout << "Не задан аргумент в командной строке.";
   else
      if  ((fp = fopen (argv[1],"r")) != NULL)
         {
            /* Открываем файл для чтения, одновременно прове-  */
            /* ряя существует ли он. Указатель fp ссылается    */
            /* теперь на файл, имя которого хранится в argv[1].*/
            while  ((ch = getc (fp)) != EOF)
            /* Получаем символ из файла и проверяем, не явля-  */
            /* ется ли этот символ символом "конец файла".     */
               putc (ch,stdout);        /* Выводим этот символ. */
            fclose (fp);                /* Закрываем файл.      */
         }
      else cout << "Файл \"" << argv[1] << "\" отсутствует.\n";
}
Текст этой программы можно взять здесь.


    Пример 3. Имитация команды copy операционной системы MS DOS.
#include <iostream.h>
#include <stdio.h>
void main ()
{
    FILE *in,*out;
    char ch;
    /* --------------------------------- */
    if ( (in=fopen ("c69_3.cpp","r")) != NULL )
       { out = fopen ("primer.cpp","w"); 
         while ((ch=getc(in)) != EOF)
                putc (ch,out); 
         fclose (in); 
         fclose (out);
        }
    else cout << "Исходный файл не найден!\n";
}
Текст этой программы можно взять здесь.


    Пример 4. Имитация команды copy операционной системы MS DOS (в командной строке задаются имя файла-источника и имя файла-приемника).
#include <iostream.h>
#include <stdio.h>
void main (int argc,char *argv[])
{
    FILE *in,*out;
    char ch;
    /* --------------------------------- */
    if  (argc<3)
         cout << "Заданы не все аргументы в командной строке.";
    else
    if ( (in=fopen (argv[1],"r")) != NULL )
       { out = fopen (argv[2],"w"); 
         while ((ch=getc(in)) != EOF)
                putc (ch,out); 
         fclose (in); 
         fclose (out);
        }
    else cout << "Исходный файл не найден!\n";
}
Текст этой программы можно взять здесь.

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

Таблица 2. Функции работы с файлами на высоком уровне
Функция
Описание
int feof (<указатель на файл>);
Проверка достижения конца файла. Возвращает истину (ненулевое значение), если указатель находится в конце файла, и ложь - в противном случае.
int fflush (<указатель на файл>);
Запись на диск содержимого буфера для заданного файла.
char *fgets(<указатель на буфер>,<максимальное число читаемых символов>,<указатель на файл>);
Последовательное чтение символов из файла до начала новой строки, или заданное количество символов, уменьшенное на 1. Прочитанные символы помещаются в буфер, начиная с ячейки, адресуемой первым параметром.
int fprintf (<указатель на файл>,<формат>,<аргументы>);
Записывает данные в файл по заданному формату. Возвращает количество записанных байтов. Если обнаружены ошибки, то возвращает EOF.
int fputs(<строка>,<указатель на файл>);
Запись заданной строки в файл.
int fread (<указатель на буфер>,<размер в байтах одного элемента>,<количество читаемых элементов>,<указатель на файл>);
Чтение данных из файла, начиная с текущего положения указателя. Возвращает число прочитанных элементов. Число прочитанных байтов равно результату функции, умноженному на число байтов в элементе. В случае ошибки возвращается нуль.
int fscanf (<указатель на файл>,<формат>,<список адресных аргументов>);
Чтение данных из файла, преобразование их в соответствующий формат и размещение в ячейки, заданные адресными аргументами.
int fseek (<указатель на файл>,<количество байтов>,<начальная позиция отсчета>);
Перемещение указателя файла на заданное количество байтов. В случае успеха возвращается нуль, в случае ошибки - ненулевое значение. Третий параметр может принимать следующие значения: SEEK_SET - отсчет идет от начала файла, SEEK_END - отсчет идет от конца файла, SEEK_CUR - отсчет идет от начала текущей позиции.
void rewind (<указатель на файл>);
Установка указателя на начало файла.


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


Предыдущий шаг Содержание Следующий шаг