Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Моя первая программа на С++.docx
Скачиваний:
3
Добавлен:
01.07.2025
Размер:
6 Мб
Скачать
☆

Дискеты 1.120000 100

лента 7.340000 150

картридж 75.000000 3

Если бы код «новая строка» не был записан на диск, текст выводился бы подряд, в одну строку на экране, и выглядел примерно так:

Дискеты 1.120000 100лента 7.340000 150картридж 75.000000 3

Заметьте, что при этом отсутствует пробел между числом, показывающим количество единиц одного това- ра, и наименованием следующего. Даже при таком способе записи можно без проблем осуществлять чте- ние из этого файла, так как компилятор в состоянии различить конец числового значения и начало стро- ки, но что произойдет, если последним значением для каждого наименования товара окажется строка с названием фирмы-производителя? Информация в файле будет выглядеть примерно таким образом:

Дискеты 1.120000 Memoryexлента

7.340000 Okaydataкартридж 75.000000 HP

и тогда при чтении данных из файла программа присоединит начало данных о следующем товаре к концу описания предыдущего. Например, данные о первом наименовании товара при этом выглядели бы так:

Дискеты 1.120000 Memoryexлента

Все выведенные на диск данные, даже значения типа int или float, хранятся в виде текстовых символов. Об этом мы будем говорить чуть позже.

Чтение форматированных файлов

Ввод информации из форматированного файла осуществляется с использованием функции 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(), записанную следующим образом:

sizeof(structure_variable)

которая автоматически определит размер указанной структуры;

    • number_of_structures— это целое число, определяющее количество структур, которые мы хотим записать в один прием; здесь всегда следует указывать число 1, если только вы не собираетесь создать массив структур и записать его одним большим блоком;

    • file_pointer— указатель на файл.

В качестве примера предположим, что вы хотите записать на диск сведения о своей коллекции компакт- дисков. Используя структуру CD, которую мы подробно разбирали в главе 11, пишем инструкцию:

Рис. 12.5. Синтаксис функции fwrite() в инструкции записи структуры CD

fwrite(&disc, sizeof(disc), 1, fp);

Выполнение этой инструкции иллюстрирует рис.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:

¶a++ae æepcue u+uru æɵuyye+a sneuwpo++ɵu usgawenacwæou "Books-shop".

Pacupocwpa+e+ue, upogaua, uepesauuca ga++on u+uru unu ee ¬acwen 3AMPE[EHª.

O æcex +apyue+uex upoca6a coo6yawa uo agpecy piracy@books-shop.com

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);

index = 0;

printf("Введите имя файла данных: "); gets(filename);

}

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);

}

Дополнение файла новыми данными

Если файл, который уже существует на диске, открыть с режимом доступа "w", вся информация, имевшая- ся в нем на текущий момент, будет уничтожена. Для того чтобы добавить данные в уже существующий на

диске файл, следует открывать его с режимом доступа "a". Фактически, большинство компиляторов по- зволяет в одной программе и создавать файл, и добавлять в него данные. Если режим доступа "a" исполь- зуется для файла, которого нет на диске, он будет создан, а если файл существует, в него будет добавле- на новая информация.

Когда вы добавляете данные в файл, вы сами должны позаботиться о том, чтобы новые данные соответст- вовали формату уже имеющейся в файле информации. Например, вы можете открыть файл, содержащий некую последовательность символов, и записать туда структуру. Она действительно будет записана в файл, так как предполагается, что вы знаете, что делаете, но при следующих попытках прочитать инфор- мацию из этого файла вы получите ошибку выполнения или какие-нибудь непонятного вида данные.