После инициализации структуры данных и буфера функция ввода читает запрошенные данные из буфера. В результате индикатор позиции устанавливается так, чтобы указывать на символ, следующий за последним прочитанным символом. Поскольку все функции ввода из семейства stdio.h используют тот же самый буфер, вызов любой такой функции возобновляет чтение там, где оно было остановлено предыдущим вызовом любой из функций.
Когда функция ввода обнаруживает, что все символы из буфера прочитаны, она запрашивает копирование из файла в буфер следующей порции данных с объемом, равным размеру буфера. В такой манере функции ввода могут читать все содержимое вплоть до конца файла. После того, как функция прочитает последний символ финальной порции данных, она устанавливает индикатор конца файла в истинное значение. Следующий вызов любой функции ввода возвратит EOF.
Функции вывода в похожем стиле производят запись в буфер. Когда буфер заполняется, данные копируются в файл.
Другие стандартные функции ввода-вывода
Стандартная библиотека ANSI содержит более трех десятков функций, образующих семейство для стандартного ввода-вывода. Мы не будем раскрывать их все, но кратко опишем еще несколько функций, чтобы дать более четкое представление о том, что вообще доступно. Для каждой функции будет приведен прототип С, отражающий ее аргументы и возвращаемое значение. Все обсуждаемые здесь функции кроме setvbuf() также доступны в реализациях, предшествующих ANSI. В разделе V приложения Б представлен полный список пакета стандартного ввода-вывода ANSI С.
ФУНКЦИЯ intungetc (int с, FILE *fp)
Функция ungetc() заталкивает символ, указанный в с, обратно во входной поток. В случае заталкивания символа во входной поток он будет прочитан следующим вызовом стандартной функции ввода (рис. 13.2).
550 глава 13
Предположим, например, что вам нужна функция, которая читает все символы до следующего двоеточия, не включая его. Вы можете применить getchar() или getc() для чтения символов до двоеточия и затем вызвать ungetc(), чтобы вернугь двоеточие обратно во входной поток. Стандарт ANSI С гарантирует только одно заталкивание за один раз. Если реализация разрешает заталкивать сразу несколько символов в строке, функции ввода прочитают их в порядке, обратном заталкиванию.

Рис. 13.2. Функция ungetc 0
ФУНКЦИЯ int fflush()
Прототип fflush() выглядит так:
int fflush(FILE *fр);
Вызов функции fflush() приводит к тому, что любые незаписанные данные в буфере вывода отправляются в выходной файл, идентифицируемый с помощью fp. Этот процесс называется сбросом буфера. Если fp — нулевой указатель, то сбрасываются все буферы вывода. Результат использования функции fflush() на входном потоке не определен. Ее можно применять с потоком обновления (для любого режима чтения- записи), при условии, что самая последняя операция, использующая поток, не была операцией ввода.
ФУНКЦИЯ int setvbuf()
Прототип setvbuf() имеет следующий вид:
int setvbuf(FILE * restrict fp, char * restrict buf, int mode, size_t size);
Функция setvbuf() устанавливает альтернативный буфер, предназначенный для применения стандартными функциями ввода-вывода. Она вызывается после того, как файл был открыт, и перед выполнением любой другой операции на потоке данных. Указатель fp идентифицирует поток, a buf указывает на используемое хранилище. Значение buf, не равное NULL, говорит о том, что буфер вы создаете самостоятельно. Например, вы могли бы объявить массив из 1024 элементов char и передать адрес этого массива. Однако если в качестве значения buf указывается NULL, то функция сама выделит память под буфер. Аргумент size сообщает setvbuf() размер этого массива, (size t — это производный целочисленный тип, который рассматривался в главе 5.) Для mode доступны следующие варианты: I0FBF означает полную буферизацию (буфер сбрасывается, когда полон), I0LBF — построчную буферизацию (буфер
Файловый ввод-вывод 551
сбрасывается, когда полон или когда в него записан символ новой строки) и IONBF — отсутствие буферизации. Функция возвращает ноль при успешном завершении и ненулевое значение в противном случае.
Предположим, что у вас есть программа, которая работает с сохраненными объектами данных, имеющими размер, скажем, по 3 000 байтов каждый. Вы могли бы с помощью setvbuf() создать буфер, размер которого кратен размеру объекта данных.
ДВОИЧНЫЙ ввод-вывод: fread() И fwrite()
Следующими в списке идут функции fread() и fwrite(), но сначала мы затронем некоторые основы. Стандартные функции ввода-вывода, которые вы применяли до сих пор, были ориентированы на текст, работая с символами и строками. А что, если в файле нужно сохранить числовые данные? Действительно, можно воспользоваться функцией fprintf() и форматом %f, чтобы сохранить значение с плавающей запятой, но тогда оно сохранится как последовательность символов. Например, код
Читать дальше