Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Файловый ввод-вывод 553
double earnings[10];
fwrite(earnings, sizeof (double), 10, fp);
Этот вызов fwrite() записывает данные из массива earnings в файл 10 порциями данных, каждая из которых имеет размер double.
Возможно, вы обратили внимание на странное объявление const void * restrict ptr в прототипе fwrite(). Проблема, связанная с функцией fwrite(), заключается в том, что ее первый аргумент не имеет фиксированного типа. Скажем, в первом примере использовался аргумент buffer, имеющий тип указателя на char, а во втором примере — аргумент earnings с типом указателя на double. В контексте прототипов ANSI С эти фактические аргументы преобразуются в тип указателя на void, который действует как своего рода универсальный тип для указателей. (До выхода ANSI С для этого аргумента применялся тип char *, требующий приведения к нему актуальных аргументов.)
Функция fwrite() возвращает количество успешно записанных элементов. Обычно оно равно nmemb, однако может быть меньше, если произошла ошибка записи.
ФУНКЦИЯ size_t fread()
Прототип функции fread() имеет следующий вид:
size_t fread(void * restrict ptr, size_t size, size_t nmemb,
FILE * restrict fp);
Функция fread() принимает такой же набор аргументов, как и fwrite(). На этот раз ptr представляет собой адрес области памяти, куда помещаются данные, прочитанные из файла, a fp идентифицирует читаемый файл. Эту функцию следует использовать для чтения данных, которые были записаны в файл с помощью fwrite(). Например, вот как восстановить массив из 10 элементов double, сохраненный в пре дыдущем примере:
double earnings[10];
fread(earnings, sizeof (double), 10, fp);
Этот вызов копирует 10 значений размера double в массив earnings.
Функция fread() возвращает количество успешно прочитанных элементов. Обычно оно равно nmemb, однако может быть меньше, если произошла ошибка записи или был достигнут конец файла.
ФУНКЦИИ int feof (FILE *fp) И int ferror (FILE *fp)
Когда стандартные функции ввода возвращают EOF, это обычно означает, что достигнут конец файла. Тем не менее, возврат EOF может также указывать на возникновение ошибки чтения. Функции feof() и ferror() позволяют проводить различие между этими двумя возможностями. Функция feof() возвращает ненулевое значение, если при последнем вызове функции ввода был обнаружен конец файла, и ноль в противном случае. Функция ferror() возвращает ненулевое значение, если произошла ошибка чтения или записи, и ноль в противном случае.
Пример использования fread() И fwrite()
Давайте воспользуемся некоторыми из этих функций в программе, которая добавляет содержимое из списка файлов в конец указанного файла. Одна из задач заключается в передаче внутрь программы информации о файлах. Это можно делать интерактивно или с помощью аргументов командной строки. Мы примем первый подход, который предполагает выполнение перечисленных ниже действий.
554 глава 13
• Запрос имени файла назначения и его открытие.
• Применение цикла для запроса исходных файлов.
• Поочередное открытие каждого исходного файла в режиме чтения и добавление его содержимого в конец файла назначения.
Чтобы проиллюстрировать работу функции setvbuf(), мы применим ее для установки другого размера буфера. Следующий этап детализации связан с открытием файла назначения. Мы будем использовать следующие шаги.
1. Открытие файла назначения в режиме добавления.
2. Если сделать это не удается, то завершение работы.
3. Установка буфера размером 4096 байтов для этого файла.
4. Если сделать это не удается, то завершение работы.
Аналогично, мы можем уточнить часть программы, отвечающую за копирование, для чего выполнить с каждым файлом такие действия.
• Если это файл назначения, то пропустить его и перейти к следующему файлу.
• Если файл не может быть открыт в режиме чтения, то пропустить его и перейти к следующему файлу.
• Добавить содержимое файла в файл назначения.
В завершение программа перейдет в начало файла назначения и отобразит его содержимое. В целях практики для копирования будут применяться функции fread() и fwrite(). Результирующий код приведен в листинге 13.5.
Листинг 13.5. Программа append.с
Файловый ввод-вывод 555
556 Глава 13
Если функции setvbuf() не удается создать буфер, она возвращает ненулевое значение, после чего программа прекращает работу. Похожий код устанавливает буфер размером 4096 байтов для файла, копируемого в текущий момент. За счет использования NULL во втором аргументе setvbuf() мы позволяем этой функции самостоятельно выделить память под буфер.
Для получения имени файла в программе применяется функция s_gets() вместо scanf(), т.к. scanf() пропускает пробельные символы и, следовательно, не сможет обнаружить пустую строку. Кроме того, в программе используется s_gets() вместо простой функции fgets(), потому что fgets() оставляет в строке символ новой строки.
Показанный ниже код предотвращает добавление содержимого файла в конец самого себя:
if (strcmp (file_src, file_app) == 0)
fputs ("Добавить файл в конец самого себя невозможною', stderr);
Аргумент file app представляет имя файла назначения, a file src — имя файла, обрабатываемого в текущий момент.
Функция append() выполняет копирование. Вместо копирования по одному байту за раз она применяет fread() и fwrite() для копирования по 4096 байтов за один раз:
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
Интервал:
Закладка: