Чтение онлайн

ЖАНРЫ

Язык программирования Си. Издание 3-е, исправленное

Ритчи Деннис М.

Шрифт:

Обращение к fopen в программе может выглядеть следующим образом:

fp = fopen(name, mode);

Первый аргумент - строка, содержащая имя файла. Второй аргумент несет информацию о режиме. Это тоже строка: в ней указывается, каким образом пользователь намерен применять файл. Возможны следующие режимы: чтение (read– "r"), запись (write– "w") и добавление (append– "a"), т. е. запись информации в конец уже существующего файла. В некоторых системах различаются текстовые и бинарные файлы; в случае последних в строку режима необходимо добавить букву "b" (binary– бинарный).

Тот факт, что некий файл, которого раньше не было, открывается на запись или добавление,

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

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

int getc(FILE *fp);

Функция getc возвращает следующий символ из потока, на который указывает *fp; в случае исчерпания файла или ошибки она возвращает EOF.

Функция putc пишет символ c в файл fp

int putc(int с, FILE *fp);

и возвращает записанный символ или EOF в случае ошибки. Аналогично getchar и putchar, реализация getc и putc может быть выполнена в виде макросов, а не функций.

При запуске Си-программы операционная система всегда открывает три файла и обеспечивает три файловые ссылки на них. Этими файлами являются: стандартный ввод, стандартный вывод и стандартный файл ошибок; соответствующие им указатели называются stdin, stdout и stderr; они описаны в ‹stdio.h›. Обычно stdin соотнесен с клавиатурой, а stdout и stderr– с экраном. Однако stdin и stdout можно связать с файлами или, используя конвейерный механизм, соединить напрямую с другими программами, как это описывалось в параграфе 7.1.

С помощью getc, putc, stdin и stdout функции getchar и putchar теперь можно определить следующим образом:

#define getchar getc(stdin)

#define putchar(c) putc((c), stdout)

Форматный ввод-вывод файлов можно построить на функциях fscanf и fprintf. Они идентичны scanf и printf с той лишь разницей, что первым их аргументом является указатель на файл, для которого осуществляется ввод-вывод, формат же указывается вторым аргументом.

int fscanf(FILE *fp, char *format,…)

int fprintf(FILE *fp, char *format,…)

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

#include ‹stdio.h›

/* cat:
конкатенация файлов, версия 1 */

main(int argc, char *argv[])

{

 FILE *fp;

 void filecopy(FILE *, FILE *);

 if (argc == 1) /* нет аргументов; копируется стандартный ввод */

filecopy(stdin, stdout);

 else

while (--argc › 0)

if ((fp = fopen(*++argv, "r")) == NULL) {

printf("cat: не могу открыть файл %s\n", *argv);

return 1;

} else {

filecopy(fp, stdout);

fclose(fp);

}

 return 0;

}

/* filecopy: копирует файл ifp в файл ofp */

void filecopy(FILE *ifp, FILE *ofp)

{

 int c;

 while ((c = getc(ifp)) != EOF)

putc(c, ofp);

}

Файловые указатели stdin и stdout представляют собой объекты типа FILE*. Это константы, а не переменные, следовательно, им нельзя ничего присваивать.

Функция

int fclose(FILE *fp)

–  обратная по отношению к fopen; она разрывает связь между файловым указателем и внешним именем (которая раньше была установлена с помощью fopen), освобождая тем самым этот указатель для других файлов. Так как в большинстве операционных систем количество одновременно открытых одной программой файлов ограничено, то файловые указатели, если они больше не нужны, лучше освобождать, как это и делается в программе cat. Есть еще одна причина применить fclose к файлу вывода, - это необходимость "опорожнить" буфер, в котором putc накопила предназначенные для вывода данные. При нормальном завершении работы программы для каждого открытого файла fclose вызывается автоматически. (Вы можете закрыть stdin и stdout, если они вам не нужны. Воспользовавшись библиотечной функцией freopen, их можно восстановить.)

7.6 Управление ошибками (stderr и exit)

Обработку ошибок в cat нельзя признать идеальной. Беда в том, что если файл по какой-либо причине недоступен, сообщение об этом мы получим по окончании конкатенируемого вывода. Это нас устроило бы, если бы вывод отправлялся только на экран, a не в файл или по конвейеру другой программе. Чтобы лучше справиться с этой проблемой, программе помимо стандартного вывода stdout придается еще один выходной поток, называемый stderr. Вывод в stderr обычно отправляется на экран, даже если вывод stdout перенаправлен в другое место. Перепишем cat так, чтобы сообщения об ошибках отправлялись в stderr.

#include ‹stdio.h›

/* cat: конкатенация файлов, версия 2 */

main(int argc, char *argv[])

{

 FILE *fp;

 void filecopy(FILE *, FILE *);

 char *prog = argv[0]; /* имя программы */

 if (argc == 1) /* нет аргументов, копируется станд. ввод */

filecopy(stdin, stdout);

 else

while (--argc › 0)

Поделиться с друзьями: