Поблочный и побайтовый режимы управления файлами, страница 2

является инверсией fopen; она нарушает связь между указателем файла и внешним именем, которое было установлено fopen, освобождая указатель файла для другого файла. Так как многие операционные системы имеют предел на число файлов, которые программа может иметь открытым одновременно, это - хорошая идея освободить указатели файла, когда они больше не необходимы, что мы делали в CAT. Имеется также другая причина для fclose на файле вывода - это смывает буфер, в котором putc собирает вывод. fclose вызывается автоматически для каждого открытого файла, когда программа заканчивается. Вы можете закрывать STDIN и STDOUT, если они не необходимы.

5.I.2. Обработка ошибок - Stderr и выход из программы Exit.

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

Чтобы обращаться с этой ситуацией лучше, второй вывод, называемый STDERR, предназначен для программы таким же образом, что STDIN и STDOUT. Вывод, написанный на STDERR, обычно появляется на экране, даже если стандартная вывод переадресован.

Чтобы улучшить ситуацию мы можем использовать функцию

            #include <stdlib.h>

            exit (number);

Где номер - целое число, какое операционная система выводит на экран после завершения программы. Эта функция находится в  <stdlib.h>.

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

#include <stdio.h>

      /* cat: concatenate files, version 2 */

      main(int argc, char *argv[])

      {    FILE *fp;

           void filecopy (FILE *, FILE *);

           char *prog = argv[0];   /* program name for errors */

           if (argc == 1) /* no args; copy standard input */

                filecopy(STDIN, STDOUT);

           else

                while (--argc > 0)

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

                          fprintf (STDERR, "%s: can't open %s\n",

                               prog, *argv);

                          exit(1);

                     } else {

                          filecopy(fp, STDOUT);

                          fclose (fp);

                     }

           if (ferror (STDOUT)) {

                fprintf(STDERR,"%s: error writing stdout\n", prog);

                exit (2);  }

           exit(O);

      }

Здесь два пути для поступления сигналов об ошибки из программы. Сначала, диагностический вывод чурез fprintf идет на STDERR, так что это находит путь к экрану вместо вывода в трубопровод или в файл вывода. Мы включили имя программы, из argv[0], в сообщении, т.о., если эта программа используется с другими, источник ошибки идентифицирован.

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

В пределах MAIN(), возвращение EXPR эквивалентно EXIT(expr). exit имеет преимущество, т.к. его можно вызвать из других функций.

Функция ferror() возвращает отличное от нуля значение, если ошибка произошла в потоке fp.

           int ferror (fp);

Хотя ошибки вывода редки, они происходят (например, если диск заполняется), так что программа должна проверить это также.

Функция feof(fp) является аналогичной ferror(); она возвращается отличное от нуля значение, если был обнаружен конец файла.

           int feof (fp);

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

5.I.3. Построчный ввод и вывод.

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

           Char *fgets (char *line, int maxline, fp);

Fgets читает следующую строку ввода (включая newline) от файла fp в строку знаков, длиной не более maxline-1 будут читаться. Строка должна быть закончена через '\0 '. Обычно fgets возвращает строку на конце которой или в случае ошибки в начале строки возвращает ПУСТОЙ УКАЗАТЕЛЬ. (Наш getline возвращает длину строки, которая является более полезной информацией; нуль означает  конец файла).

При выводе функция fputs пишет строку (которая не должны содержать newline):

           int fputs (char *line, fp);

Функция возвращает EOF, если ошибка происходит, и ноль иначе.

Функции библиотеки gets и puts,  подобны fgets и fputs, но работают на STDIN и STDOUT. gets удаляет терминал '\n ', а puts добавляет его.

Чтобы показать, что не имеется ничего специального относительно функций  fgets и fputs, вот как они описаны в стандартной библиотеке  нашей системы:

      /* fgets: get at most n chars from iop */

      char *fgets (char *s, int n, FILE *iop)

      {   register int c;

           register char *cs;

           cs = s;

           while (--n > 0 && (c = getc(iop)) != EOF)

                if ((*cs++ = c) == '\n')

                     break;

           *cs = '\0';

           return (c == EOF && cs == s) ? NULL : s;

      }

      /* fputs: put string s on file iop */

      int fputs(char *s, FILE *iop)

      {    int c;

           while (c = *s++)