sem08 - работа с бинарными файлами на уровне функций стандартной библиотеки (1114922), страница 2
Текст из файла (страница 2)
Поэтому размер одного элементаданных всегда нужно задавать равным 1, а возвращаемое значение сравнивать с запрошенным количеством байт. Здесь возможны следующие ситуации:• Считано 0 байт. Это значит, что наступил конец файла, или возникла ошибка чтения.4Чтобы узнать, завершилась ли функция fread по ошибке или по концу файла, нужноиспользовать функции feof и ferror.• Считано байт меньше, чем запрошено, но количество байт кратно размеру одного элемента данных.
В этом случае нужно обработать считанное количество элементов.• Считано байт меньше, чем запрошено, и количество байт не кратно размеру одногоэлемента данных. В этом случае можно выдать ошибку о нарушении формата входныхданных.• Считано байт ровно столько, сколько запрошено.
Нужно обработать считанные элементы.1.4.3 Запись — функция fwrite#include <stdio.h>size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *f);Функция fwrite записывает данные в дескриптор потока. Параметр buf — это адресначала буфера, в котором хранятся записываемые данные, size — это размер одного элемента данных, а nmemb — это количество элементов данных, которые необходимо записать.f — дескриптор потока, в который ведётся запись.Общее количество байт, которые необходимо записать, вычисляется аналогично функции fread. Возвращаемое значение также получается делением нацело действительно записанного количества байт на размер одного элемента данных.1.4.4 Позиционирование в файле#include <stdio.h>#define SEEK_SET 0#define SEEK_CUR 1#define SEEK_END 2int fseek(FILE *stream, long offset, int whence);long ftell(FILE *stream);Функция ftell позволяет получить смещение указателя на текущее положение в файлев байтах относительно начала файла.
При ошибке функция возвращает -1.Функция fseek позволяет переместить указатель на текущее положение в файле. Параметр stream задаёт дескриптор потока, связанный с файлом, параметр offset задаётсмещение в байтах, а параметр whence — точку, от которой отсчитывается смещение. Этотпараметр может принимать три значения, перечисленные ниже.SEEK_SET смещение отсчитывается от начала файлаSEEK_CUR смещение отсчитывается от текущего положения в файлеSEEK_END смещение отсчитывается от конца файлаЕсли новое положение в файле находится за текущим концом файла, и файл открыт назапись или чтение/запись, файл расширяется нулями до требуемого размера. Если новоеположение в файле находится до начала файла, возвращается ошибка.5При успешном завершении функция fseek возвращает 0, а при ошибке — -1.Обратите внимание, что функции позиционирования могут быть неприменимы к стандартным потокам, потому что стандартные потоки могут быть связаны с устройствами, которые не допускают произвольное позиционирование (например, терминалы).1.4.5 Изменение размера файла#include <stdio.h>#include <unistd.h>int truncate(const char *path, off_t length);Функция truncate позволяет изменить (увеличить или уменьшить) размер существующего файла с путём path.
Новый размер файла будет равен значению, заданному в параметре length. Если файл увеличивается в размере, новая часть инициализируется нулями.Если файл уменьшается, старый остаток файла теряется.1.4.6 Вычисление размера файлаПриведённая ниже функция позволяет получить размер файла по его имени. В качествепараметра ей передаётся имя файла, она возвращает размер файла при успешном завершении и -1 при ошибке.#include <stdio.h>long fsize(char const *path){FILE *f = 0;long size;if (!(f = fopen(path, "r"))) return -1;if (fseek(f, 0, SEEK_END) < 0) goto error;if ((size = ftell(f)) != -1) goto error;fclose(f);return size;error:if (f) fclose(f);return -1;}1.4.7 Пример программыСледующая программа принимает в качестве параметров командной строки список имёнфайлов.
Предполагается, что эти файлы содержат целые числа в бинарном виде. Программаувеличивает все числа в файле на единицу.#include <stdio.h>int process_file(char const *path){6FILE *f = 0;intdata;intrb;if (!(f = fopen(path, "r+b"))) {fprintf(stderr, "cannot open file ‘%s’\n", path);return 1;}while ((rb = fread(&data, 1, sizeof(data), f)) == sizeof(data)) {if (fseek(f, -sizeof(data), SEEK_CUR) < 0) {fprintf(stderr, "seek error in ‘%s’\n", path);fclose(f);return 1;}data++;if (fwrite(&data, 1, sizeof(data), f) != sizeof(data)) {fprintf(stderr, "write error to ‘%s’\n", path);}}if (ferror(f)) {fprintf(stderr, "read error from ‘%s’\n", path);fclose(f);return 1;}if (rb > 0) {fprintf(stderr, "format error in ‘%s’\n", path);fclose(f);return 1;}if (fclose(f) < 0) {fprintf(stderr, "write error to ‘%s’\n", path);return 1;}return 0;}int main(int argc, char *argv[]){int retval = 0;int i;for (i = 1; i < argc; i++) {retval |= process_file(argv[i]);}return retval;}1.4.8 Упражнения1.
Разберите следующие деклараторыstruct foo *f(int (*)(int));7const char * (*x)[2][2];unsigned long * const (* const z[2])[4];2. В аргументах командной строки задаётся имя бинарного файла, хранящего дерево поиска, и целое число - ключ поиска в файле. Необходимо напечатать значение, соответствующее заданному ключу, хранящееся вместе с ключём в бинарном дереве поиска вфайле.Бинарное дерево поиска в файле устроено следующим образом. Каждая запись занимает 4 слова (по 32 бита каждое слово). Первое слово — это ключ, второе слово — этозначение, третье слово — это номер записи, соответствующей вершине левого поддерева, и четвёртое слово — это номер записи, соответствующей вершине правого поддерева.
Нулевая запись в файле не используется, и зарезервирована для обозначения«нулевого указателя». Корень всего дерева находится в первой записи.8.