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

Если файл, который уже существует на диске, открыть с режимом доступа "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", что позволяет записывать в

Дополнение файла новыми данными - student2.ru
Рис. 12.6. Функция fprintf() записывает числовые значенияв виде текстовых символов

него данные. Если второй файл невозможно открыть, то перед завершением программы сначала закрывается первый файл. Это дает нам гарантию того, что первый файл, если он был успешно открыт, не окажется поврежден в момент выхода из программы.

Функция fprintf() записывает все данные в виде текста. Например, если использовать fprintf() для записи числа 34.23 на диск, пять символов будут записаны так, как это показано на рис.12.6. Если в дальнейшем для чтения данных из файла используется функция fscanf(), символы будут преобразованы в числовое значение и в таком виде записаны в переменную.

Вследствие того, что функция fprintf() записывает данные в виде текста, чтение из файла можно осуществлять и с помощью функций getc(), fgetc() или fgets(). Однако эти функции будут читать информацию в виде «печатных» символов. Например, если использовать функцию fgets(), числа будут считываться в виде символов, являющихся частью строки. При отображении на экране или печати на принтере данных, прочитанных с использованием функции fgets() или fgetc(), вы будете лишены возможности выполнения арифметических операций над отдельными элементами данных.

Двоичный формат

Для сохранения числовых переменных в двоичном формате используется функция fwrite(). Записанные таким образом данные на диске займут столько

Дополнение файла новыми данными - student2.ru
Компиляторы Си++ и многие компиляторы, поддерживающие стандарт ANSI языка Си, позволяют создавать форматированные двоичные файлы для хранения числовых данных. Файл создается с режимом доступа "wb" и читается с режимом доступа "rb". Символ b указывает на двоичный формат. Если открыть файл с таким режимом доступа, можно записывать в файл целочисленные значения с помощью функции putw() и читать их из файла с помощью функции getw().


же места, сколько и в памяти. Если просмотреть содержимое такого файла с помощью команды 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(), конечно, если ваш компилятор это позволяет. Как только искомые данные найдены, они выводятся на экран, после чего файл закрывается.

Дополнение файла новыми данными - student2.ru Функции произвольного доступа
Компиляторы Си++ и многие компиляторы Си, поддерживающие стандарт ANSI, имеют функции произвольного доступа к файлу. Произвольный доступ означает, что вы можете перейти непосредственно к определенному месту файла для чтения или внесения изменений в данные, расположенные именно в этом месте. Перемещение указателя файла в заданную позицию выполняет функция fseek(). Если за ней следует, например, функция fread(), то она будет читать данные, начиная с позиции, отмеченной файловым указателем. Кроме того, функция ftell() сообщает текущее положение указателя, а функция rewind() переносит указатель в начало файла.

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

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

Дополнение файла новыми данными - student2.ru <> Вопросы
  1. Что такое файловый буфер?
  2. Как используется файловая структура?
  3. Для чего в программах используют указатель на файл?
  4. Опишите, в чем заключаются различия между режимами доступа "r", "w" и "a"?
  5. Почему необходимо закрыть файл перед завершением работы программы?
  6. Как вы будете выводить числовые данные?
  7. Как напечатать данные на принтере?
  8. В чем заключается различие между функциями fprintf() и fwrite()?
  9. Как осуществить печать структур?
  10. Для чего служит функция sizeof()?
Дополнение файла новыми данными - student2.ru <> Упражнения
  1. Напишите программу, в которой функция fputs() используется для создания файла, содержащего названия кинофильмов.
  2. Напишите программу, которая читает названия кинофильмов (упражнение1) в массив строк.
  3. Напишите программу, в которой функция fprintf() используется для создания файла инвентарной описи, содержащей сведения о наименовании товара, его цене и количестве единиц, имеющихся в наличии.
  4. Напишите программу, которая читает файл инвентарной описи, созданный в упражнении 3.
  5. Отредактируйте программы из упражнений 3 и 4 так, чтобы они читали данные как структуры.
6. Объясните, почему следующая программа написана неверно: #include "stdio.c" main() { FILE fp; char letter; if ((fp = fopen("MYFILE", "w")) == NULL) { puts("Невозможно открыть файл"); exit(); } do { letter = getchar(); fputc(letter, fp); } while(letter != '\n'); fclose(fp); }

Наши рекомендации