Чтение форматированных файлов
Ввод информации из форматированного файла осуществляется с использованием функции fscanf(). Она работает аналогично функции scanf() за исключением того, что fscanf() осуществляет ввод данных не с клавиатуры, а из
файла. К несчастью, использование fscanf() имеет те же ограничения, что и применение scanf(). Эта функция не может читать строки, содержащие пробелы, и если данные во входном потоке не будут соответствовать указателям в строке формата, она вернет ошибочные значения.
В Листинге 12.4 приводится текст программы, которая читает данные из форматированного файла, содержащего сведения об инвентарной описи. Заметьте, что цикл while повторяется до тех пор, пока функция fscanf() не возвратит значение EOF, которое будет свидетельствовать о достижении конца файла.
Листинг 12.4. Чтение форматированного текста из файла.
/*fscanf.c*/#include "stdio.h"main() { FILE *fp; char name[20]; int quantity; float cost; if ((fp = fopen("MYFILE", "r")) == NULL) { puts("Невозможно открыть файл"); exit(); } while (fscanf(fp, "%s%f%d", name, &cost, &quantity) != EOF) { printf("Наименование товара: %s\n", name); printf("Цена: %.2f\n", cost); printf("Количество единиц: %d\n", quantity); } fclose(fp); }Работа со структурами
Одним из способов преодолеть ограничения функции scanf() является объединение элементов данных в структуру с тем, чтобы впоследствии осуществлять ввод и вывод структур целиком. Структуру можно записать на диск с помощью функции fwrite() и прочитать из файла с помощью функции fread().
Синтаксис функции fwrite() такой:
fwrite(&structure_variable, structure_size, number_of_structures, file_pointer);На первый взгляд, эта инструкция выглядит несколько устрашающей, но на самом деле использовать ее очень легко:
- &structure_variable — имя структурной переменной с оператором получения адреса, сообщающим компилятору стартовый адрес информации, которую мы хотим записать на диск;
- structure_size — это количество символов в структуре; не обязательно подсчитывать его самому, для этого можно использовать библиотечную функцию sizeof(), записанную следующим образом:
которая автоматически определит размер указанной структуры;
- number_of_structures — это целое число, определяющее количество структур, которые мы хотим записать в один прием; здесь всегда следует указывать число 1, если только вы не собираетесь создать массив структур и записать его одним большим блоком;
- file_pointer — указатель на файл.
Рис. 12.5. Синтаксис функции fwrite() в инструкции записи структуры CD
Выполнение этой инструкции иллюстрирует рис.12.5.
Текст программы, которая вводит данные в структуру CD, а затем сохраняет ее на диске, приведен в Листинге12.5. Для ввода имени создаваемого файла используется функция gets(). Переменная, в которой хранится имя файла, используется функцией fopen() для того, чтобы открыть файл.
Информация о каждой структуре CD вводится с клавиатуры, после чего структура целиком записывается на диск.
Листинг 12.5. Запись структуры CD.
/*fwrite.c*/#include "stdio.h"main() { FILE *fp; struct CD { char name[20]; char description[40]; char category[12]; float cost; int number; } disc; char filename[25]; printf("Введите имя файла, который вы желаете создать: "); gets(filename); if ((fp = fopen(filename, "w")) == NULL) { printf("Невозможно открыть файл %s\n", filename); exit(); } puts("Введите сведения о диске\n"); printf("Введите название диска: "); gets(disc.name); while (strlen(disc.name) > 0) { printf("Введите описание: "); gets(disc.description); printf("Введите категорию: "); gets(disc.category); printf("Введите цену: "); scanf("%f", &disc.cost); printf("Введите номер ячейки: "); scanf("%d", &disc.number); fwrite(&disc, sizeof(disc), 1, fp); printf("Введите название: "); gets(disc.name); } fclose(fp); }Чтение структур
Для того чтобы прочитать структуру целиком, используется функция fread(). Она имеет следующий синтаксис:
fread(&structure_variable, structure_size, number_of_structures, file_pointer);За исключением имени функции эта инструкция полностью совпадает с записью функции fwrite(). Программа, в которой из файла считывается структура CD, приведена в Листинге12.6. Для чтения данных используется цикл while:
while (fread(&disc, sizeof(disc), 1, fp) == 1)Функция fread() возвращает значение, соответствующее количеству успешно прочитанных структур. Так как в аргументе функции мы указали, что читать следует по одной структуре, функция возвращает значение 1. Цикл while будет выполняться до тех пор, пока считывание структур с диска проходит успешно. Если чтение структуры становится невозможным, например потому, что достигнут конец файла, функция возвращает значение 0, и выполнение цикла прекращается.
Листинг 12.6. Чтение структуры CD с диска.
/*fread.c*/#include "stdio.h"main() { FILE *fp; struct CD { char name[20]; char description[40]; char category[12]; float cost; int number; } disc; char filename[25]; printf("Введите имя файла, который желаете открыть: "); gets(filename); if ((fp = fopen(filename, "r")) == NULL) { printf("Невозможно открыть файл %s\n", filename); exit(); } while (fread(&disc, sizeof(disc), 1, fp) == 1) { puts(disc.name); putchar('\n'); puts(disc.description); putchar('\n'); puts(disc.category); putchar('\n'); printf("%f", disc.cost); putchar('\n'); printf("%d", disc.number); } fclose(fp); }В табл. 12.1 собраны все описанные способы ввода и вывода данных и показаны значения, которые возвращает каждая функция при невозможности продолжения чтения или записи данных.
Таблица 12.1. Функции ввода в файл и вывода из файла.
Чтение в массив
Во всех программах, приведенных до настоящего момента в качестве примера, выполнялось чтение данных из файла и отображение вводимой информации на экране. Однако если считывать данные в переменные, с ними можно выполнять любые операции, например, использовать их для записи в массив.
В Листинге 12.7 приведен текст программы, осуществляющей чтение информации из файла, содержащего данные о коллекции компакт-дисков, в массив структур CD (предполагается, что их количество не превышает20). Индекс используется для того, чтобы каждая считанная из файла структура сохранялась в отдельном элементе массива disc. После того как очередная структура прочитана и выведена на экран, стоимость очередного диска добавляется к сумме, отражающей общую стоимость коллекции, а значение индекса и счетчика увеличивается за счет выполнения следующих инструкций:
total = total + disc[index].cost;index++;count++;Если бы нас интересовала только информация об общей стоимости и количестве экземпляров коллекции, можно было бы читать данные в структурную переменную, не используя массив, и просто подсчитывать значения переменных total и count. Однако если данные будут считаны в массив, вы сможете произвольным образом обращаться к структурам и печатать любую информацию.
Заметьте, что запрос о вводе имени файла в программе повторяется до тех пор, пока не будет введено имя файла, который действительно можно открыть.
Листинг 12.7. Чтение структуры в массив.
/*rarray.c*/#include "stdio.h"main() { FILE *fp; struct CD { char name[20]; char description[40]; char category[12]; float cost; int number; } disc[20]; int index, count; float total; count = 0; total = 0; char filename[25]; printf("Введите имя файла данных: "); gets(filename); while ((fp = fopen(filename, "r")) == NULL) { printf("Невозможно открыть файл %s\n", filename); printf("Введите имя файла данных: "); gets(filename); } index = 0; while (fread(&disc[index], sizeof(disc[index]), 1, fp) == 1) { puts(disc[index].name); putchar('\n'); puts(disc[index].description); putchar('\n'); puts(disc[index].category); putchar('\n'); printf("%f", disc[index].cost); putchar('\n'); printf("%d", disc[index].number); total = total + disc[index].cost; index++; count++; } fclose(fp); printf("Общая стоимость коллекции составляет %.2f\n", total); printf("Коллекция содержит %.d дисков\n", count); }
|