void append(FILE ‘source, FILE *dest)
{
size_t bytes;
static char temp[BUFSIZE]; // выделить память один раз
while ((bytes = fread(temp,sizeof(char),BUFSIZE,source)) > 0) fwriteltemp, sizeof (char), bytes, dest);
}
Поскольку файл, указанный посредством dest, открыт в режиме добавления, содержимое исходных файлов по очереди добавляется в конец файла dest. Обратите внимание, что массив temp имеет статическую продолжительность хранения (это значит, что память под него выделяется на этапе компиляции, а не каждый раз, когда вызывается append()) и область видимости в пределах блока (т.е. он является закрытым для данной функции).
В примере используются файлы в текстовом режиме; путем применения режимов "ab+" и "rb" можно было бы обрабатывать двоичные файлы.
Произвольный доступ С ДВОИЧНЫМ ВВОДОМ-ВЫВОДОМ
Произвольный доступ чаще всего применяется с двоичными файлами, записанными с использованием двоичного ввода-вывода, поэтому давайте рассмотрим короткий пример. Программа в листинге 13.6 создает файл с числами типа double и затем предоставляет доступ к его содержимому.
Листинг 13.6. Программа randbin.c

Файловый ввод-вывод 557

Первым делом программа создает массив и помещает в него ряд значений. Затем она создает файл по имени numbers .dat в двоичном режиме и применяет функцию fwrite() для копирования содержимого массива в этот файл. 64-битовая последовательность для каждого значения double копируется из памяти в файл. Вы не сможете прочитать результирующий двоичный файл в текстовом редакторе, т.к. эти значения не транслируются в строки. Однако каждое значение хранится в файле точно так же, как оно хранилось в памяти, поэтому точность не теряется. Более того, каждое значение занимает 64 бита пространства в файле, благодаря чему легко вычислять местонахождение каждого значения.
Во второй части программы файл открывается для чтения и пользователю предлагается ввести индекс значения. Умножение значения индекса на количество байтов, занимаемых типом double, дает позицию в файле. Далее в программе вызывается fseek() для перехода в эту позицию и fread() для чтения значения из этого места. Обратите внимание на отсутствие спецификаторов формата. Взамен fread() копирует 8 байтов, начиная с заданной позиции, в ячейку памяти, указанную &value. После этого программа использует функцию printf() для отображения value.
558 глава 13
Ниже показаны результаты пробного запуска:
Введите индекс в диапазоне 0-999.
500
По этому индексу находится значение 50000.001996.
Введите следующий индекс (или значение за пределами диапазона для завершения):
900
По этому индексу находится значение 90000.001110.
Введите следующий индекс (или значение за пределами диапазона для завершения):
О
По этому индексу находится значение 1.000000.
Введите следующий индекс (или значение за пределами диапазона для завершения):
-1
Программа завершена.
Ключевые понятия
Программа С рассматривает ввод как поток байтов; источником этого потока может быть файл, устройство ввода (такое как клавиатура) или даже вывод из другой программы. Подобным же образом программа С трактует вывод как поток байтов; местом назначения может быть файл, экран монитора и т.д.
То, как в С интерпретируется входной или выходной поток байтов, зависит от применяемых функций ввода-вывода. Программа может читать и сохранять байты без их изменений либо интерпретировать байты как символы, которые, в свою очередь, могут быть интерпретированы как обычный текст или текстовое представление чисел. Аналогично, при выводе используемые функции определяют, передаются ли двоичные значения без изменений либо преобразуются в текст или текстовое представление чисел. Если есть числовые данные, которые вы хотите сохранять и затем восстанавливать без потери точности, применяйте двоичный режим и функции fread() и fwrite(). Если вы сохраняете текстовую информацию и хотите создать файл, который может быть просмотрен с помощью обычных текстовых редакторов, используйте текстовый режим и такие функции, как getc() и fprintf().
Для доступа в файл вам потребуется создать указатель файла (типа FILE *) и связать его с конкретным именем файла. Для работы с файлом в последующем коде будет применяться этот указатель, а не имя файла.
Важно понимать, как в С поддерживается концепция конца файла. Обычно в программе для чтения файла используется цикл для чтения входных данных до тех пор, пока не будет достигнут конец файла. Функции ввода С не обнаруживают конец файла до тех пор, пока они не предпримут попытку чтения за концом файла. Это означает, что проверка на предмет конца файла должна производиться непосредственно после попытки чтения. В качестве руководства можете применять модели ввода из двух файлов, помеченные как “правильное проектное решение” в разделе “Конец файла” данной главы.
Читать дальше