Дополнение файла новыми данными
Если файл, который уже существует на диске, открыть с режимом доступа "w", вся информация, имевшаяся в нем на текущий момент, будет уничтожена. Для того чтобы добавить данные в уже существующий на диске файл, следует открывать его с режимом доступа "a". Фактически, большинство компиляторов позволяет в одной программе и создавать файл, и добавлять в него данные. Если режим доступа "a" используется для файла, которого нет на диске, он будет создан, а если файл существует, в него будет добавлена новая информация.
Когда вы добавляете данные в файл, вы сами должны позаботиться о том, чтобы новые данные соответствовали формату уже имеющейся в файле информации. Например, вы можете открыть файл, содержащий некую последовательность символов, и записать туда структуру. Она действительно будет записана в файл, так как предполагается, что вы знаете, что делаете, но при следующих попытках прочитать информацию из этого файла вы получите ошибку выполнения или какие-нибудь непонятного вида данные.
Текстовый и двоичный форматы
Функции putc(), fputc() и fputs() служат для вывода текста. Если вы просмотрите дисковый файл, используя команду TYPE, то увидите точно такие же символы, какие ввели. Файл можно создать, использовав любую из этих функций, а затем прочитать из него с помощью функций getc(), fgetc() или fgets(). При этом функции, осуществляющие посимвольное чтение, будут вводить по одному символу, даже если изначально в файл была записана строка с помощью функции fputs(). Аналогично, функции, предназначенные для построчного чтения из файла, будут вводить данные целыми строками, даже если информация в файл была записана посимвольно.
В Листинге 12.8 приведен текст программы, которая копирует содержимое одного файла в другой, одновременно отображая его на экране. Программа будет работать с любым файлом, безотносительно того, как именно он был создан. В программе определены два указателя на файлы, так как мы обращаемся к двум файлам одновременно.
Листинг 12.8. Программа копирования содержимого файлов.
/*filecopy.c*/#include "stdio.h"main() { FILE *fp1, *fp2; char infile[25], outfile[25]; int letter; printf("Введите имя файла для чтения: "); gets(infile); if ((fp1 = fopen(infile, "r")) == NULL) { printf("Невозможно открыть файл %s", infile); exit(); } printf("Введите имя файла для записи: "); gets(outfile); if ((fp2 = fopen(infile, "w")) == NULL) { printf("Невозможно открыть файл %s", outfile); fclose(fp1); exit(); } while ((letter = fgetc(fp1)) != EOF) { putchar(letter); fputc(letter, fp2); } fclose(fp1); fclose(fp2); }Первый файл открывается с режимом доступа "r", чтобы можно было прочитать из него данные. Если файл невозможно открыть, программа завершается. Второй файл открывается с режимом доступа "w", что позволяет записывать в
Рис. 12.6. Функция fprintf() записывает числовые значенияв виде текстовых символов
него данные. Если второй файл невозможно открыть, то перед завершением программы сначала закрывается первый файл. Это дает нам гарантию того, что первый файл, если он был успешно открыт, не окажется поврежден в момент выхода из программы.
Функция fprintf() записывает все данные в виде текста. Например, если использовать fprintf() для записи числа 34.23 на диск, пять символов будут записаны так, как это показано на рис.12.6. Если в дальнейшем для чтения данных из файла используется функция fscanf(), символы будут преобразованы в числовое значение и в таком виде записаны в переменную.
Вследствие того, что функция fprintf() записывает данные в виде текста, чтение из файла можно осуществлять и с помощью функций getc(), fgetc() или fgets(). Однако эти функции будут читать информацию в виде «печатных» символов. Например, если использовать функцию fgets(), числа будут считываться в виде символов, являющихся частью строки. При отображении на экране или печати на принтере данных, прочитанных с использованием функции fgets() или fgetc(), вы будете лишены возможности выполнения арифметических операций над отдельными элементами данных.
Двоичный формат
Для сохранения числовых переменных в двоичном формате используется функция fwrite(). Записанные таким образом данные на диске займут столько
|
же места, сколько и в памяти. Если просмотреть содержимое такого файла с помощью команды TYPE, мы увидим на месте числовых значений бессмысленные буквы и значки. Это ASCII-символы, эквивалентные записанным в файл значениям.
Для чтения файла, записанного с помощью fwrite(), следует использовать функцию fread(). Вводить данные следует в структуру, имеющую строение, соответствующее сохраненным ранее данным. Структура может иметь другое имя, имена членов структуры тоже могут отличаться, но порядок, типы и размеры членов обеих структур должны совпадать.
Печать данных
С технической точки зрения вывести данные на принтер можно с помощью любой функции вывода: посимвольно, построчно, форматированными строками или структурами. Единственное, что необходимо, — это указать имя файла "prn" и режим доступа "w".
Однако «поструктурная» печать с помощью функции fwrite() практически не используется, так как числовые данные при этом будут напечатаны в двоичном формате в виде загадочных символов. Вместо этого для печати структур используется функция fprintf(), как это показано в Листинге12.9. В этой программе открываются два файла: дисковый файл открывается для чтения, а файл принтера — для вывода.
Листинг 12.9. Чтение и печать содержимого дискового файла.
/*fread1.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(); } if((ptr = fopen("PRN", "w")) == NULL) { printf("Принтер не готов к работе\n", filename); fclose(fp); exit(); } while (fread(&disc, sizeof(disc), 1, fp) == 1) { fprintf(ptr, "Название диска %s\n", disc.name); fprintf(ptr, "Описание: %s\n", disc.description); fprintf(ptr, "Категория: %s\n", disc.category); fprintf(ptr, "Стоимость: %6.2f\n", disc.cost); fprintf(ptr, "Номер п/п: %d\n", disc.number); fprintf(ptr, "\n\n"); } fclose(ptr); fclose(fp); }Каждая структура целиком вводится функцией fread(), после чего отдельные члены структуры печатаются с использованием функции fprintf(). Функция fread() может читать строки, включающие пробелы, поэтому ее применение предпочтительнее, чем использование функции fscanf().
Инструкции
fprintf(ptr, "\n\n");выводят по две пустые строки между отдельными структурами CD.
Проектирование программы
Знание того, как осуществляется запись в дисковый файл и чтение из него, открывает перед вами возможность создания сложных приложений. В этой главе все программы, которые демонстрировали ввод данных из дискового файла, читали его целиком. Но можно представить себе ситуацию, когда вы захотите поступить с данными каким-либо другим образом.
Например, вам может понадобиться просмотреть дисковый файл в поисках определенной записи. В этом случае следует открыть файл с режимом доступа "r", а потом использовать цикл для постепенного ввода данных, структура за структурой или строка за строкой в зависимости от того, к какому типу относится информация, записанная в файл. Во время каждого прохождения цикла значения вводимых данных сравниваются с искомыми. Для проверки значений строк используйте функцию strcmp(), конечно, если ваш компилятор это позволяет. Как только искомые данные найдены, они выводятся на экран, после чего файл закрывается.
|
Функции работы с файлами, описанные в этой главе, выполняют последовательные операции. Это означает, что они выполняют чтение файла от его начала. Вы можете использовать режим доступа "a" для того, чтобы добавить данные в конец файла, но вы не можете перейти прямо к определенной позиции в файле, чтобы изменить хранящуюся там информацию.
Это не означает, что информацию, хранящуюся в файле, вообще нельзя изменить. Существует алгоритм, позволяющий обращаться к содержимому файла последовательно. Вы познакомитесь с этим и другими алгоритмами в многочисленных примерах, которые приведены в следующей главе.
<> | Вопросы |
|
<> | Упражнения |
|