Чтение символа

Запись символа

Система ввода/вывода ANSI С определяет две эквивалентные функции, выводящие символ - putc() и fputc(). (На самом деле putc() реализована в виде макроопределения.) Поддержка двух идентич­ных функций необходима для сохранения совместимости со старыми версиями С.

Функция putc() используется для записи символов в поток, ранее открытый для записи с помо­щью функции fopen(). Прототип для putc() следующий:


int putc(int ch, FILE *fp);

где fp — это указатель на файл, возвращенный fopen(), a ch - выводимый символ. Указатель на файл указывает putc(), в какой файл следует писать. По историческим причинам ch определена как int, но используется только младший байт.

Если putc() выполнена успешно, она возвращает выведенный символ. В противном случае воз­вращает EOF.

 

Имеется две эквивалентные функции, предназначенные для ввода символа - getc() и fgetc(). Под­держка двух идентичных функций необходима для сохранения совместимости со старыми верси­ями С.

Функция getc() используется для чтения символов из потока, открытого на чтение с помощью fopen(). Прототип getc() следующий:


int getc(FILE *fp);

где fp - это указатель на файл типа FILE *, возвращенный fopen(). По традиции getc() возвращает целое, но старший байт установлен в 0.

Функция getc() возвращает EOF при достижении конца файла. Для чтения текстового файла до конца следует использовать следующий код:

ch = getc(fp);
while(ch!=EOF) {
ch = getc(fp);
}

fclose()

Функция fclose() используется для закрытия потока, ранее открытого с помощью fopen(). Она сохраняет в файл данные, находящиеся в дисковом буфере, и выполняет операцию системного уровня по закрытию файла. Вызов fclose() освобождает блок управления файлом, связанный с потоком, и делает его доступным для повторного использования.

Функция fclose() имеет прототип:

int fclose(FILE *fp);

где fp - это указатель на файл, возвращенный fopen(). Если возвращен 0, то это означает, что операция закрытия выполнена успешно, а если EOF, то, значит, была ошибка.

Использование fopen(), getc(), putc() и fclose()

Функции fopen(), getc(), putc() и fclose() составляют минимальный набор файловых операций. Ниже приведен простой пример использования putc(), fopen() и fclose() в программе ktod. Она просто читает символы с клавиатуры и записывает их в файл, пока не встретится точка. Имя файла указывается в командной строке. Например, если назвать программу ktod, а затем набрать ktod test, то можно будет ввести строчки текста в файл test.

/* ktod: ключ к диску */
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char ch;
if (argc!=2) {
printf("You forgot to enter the filename.");
return 1;
}
if((fp=fopen(argv[l], "w")) == NULL) {
printf("Cannot open file.");
return 1;
}
do {
ch = getchar(); putc(ch, fp) ;
} while (ch!='.');
fclose(fp);
return 0;
}

Программа dtos читает любой текстовый файл и выводит его содержимое на экран. В команд­ной строке следует указать имя файла.

/* dtos: диск на экран */
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE * fp;
char ch;
if (argc!=2) {
printf("You forgot to enter the filename.");
return 1;
}
if((fp=fopen(argv[1], "r")) == NULL) {
printf("Cannot open file.");
return 1;
}
ch = getc(fp); /* чтение одного символа */
while (ch!=EOF) {
putchar(ch); /* вывод на экран */
ch = getc(fp);
}
fclose(fp);
return 0;
}

Использование feof()

Как утверждалось ранее, файловая система С может оперировать двоичными данными. Когда файл открыт для двоичного ввода, может быть прочитано целочисленное значение, равное EOF. В результате getc() будет отображать состояние наличия конца файла, хотя физический конец еще не достигнут. Для разрешения данной проблемы в С имеется функция feof(), используемая для определения конца файла при чтении двоичных данных. Она имеет следующий прототип:

int feof(FILE *fp);

где fp идентифицирует файл. Функция feof() возвращает не 0, если достигнут конец файла, в противном случае она возвращает 0. Следовательно, следующий код читает двоичный файл, пока не встретится метка конца файла:

while(!feof(fp)) ch = getc(fp);

Данный метод может применяться не только к двоичным, но и к текстовым файлам.

Следующая программа копирует файл любого типа. Следует обратить внимание, что файлы открываются в двоичном режиме, и feof() используется для проверки наличия конца файла:

/* данная программа копирует один файл в другой */
#include <stdio.h>

void main(void)

{char ch;

FILE *in, *out;

if( (in=fopen("5.txt", "rt")) == NULL)

{

printf ("Cannot open source file.");

}

if((out=fopen("6.txt" , "wt")) == NULL)

{

printf ("Cannot open destination file.");

}

 

while (!feof (in)) // копирование файла

{

ch = getc(in);

putc(ch, out);

}

fclose(in);

fclose(out);

return 0;

}

Работа со строками: fgets() и fputs()

Файловая система ввода/вывода С содержит две функции, которые могут читать или писать строки в поток - fgets() и fputs(). Они имеют следующие прототипы:

int fputs(const char *str, FILE *fp);

char *fgets(char *str, int длина, FILE *fp);

Функция fputs() во многом подобна puts(), за тем исключением, что она записывает строку в указанный поток. Функция fgets() читает строку из указанного потока, пока не встретится символ новой строки или не будет прочитано (длина - 1) символов. Если прочитан символ новой строки, то он станет частью строки (в противоположность gets()). В обоих случаях результирующая строка завершается нулевым символом. Функция возвращает str в случае успеха и нулевой указатель - в случае ошибки.
Можно использовать fgets() как альтернативу gets(). Чтобы сделать это, надо просто указать stdin как указатель на файл. Например, следующая программа читает до 79 символов, полученных из стандартного ввода:

#include <stdio.h>

#include <conio.h>

void main(void)

{

char s[80];

FILE *file;

printf("Enter a string: ");

fgets(s, 80, stdin);

printf ("Here is your string: %s", s);

file=fopen("5.txt","rt");

fgets(s, 80, file);

printf ("Here is your string: %s", s);

_getch();

}

Преимущество использования fgets() над gets() состоит в том, что можно предотвратить переполнение массива ввода. Массив может содержать символ новой строки.

fread() и fwrite()

Файловая система ANSI С предоставляет две функции, позволяющие читать и писать блоки данных - fread() и fwrite(). Они имеют следующие прототипы:

size_t fread(void *буфер, size_t число_байт, size_t объем, FILE *fp);

size_t fwrite(const void *буфер, size_t число_байт, size_t объем, FILE *fp);

В случае fread() буфер - это указатель на область памяти, которая получает данные из файла. В случае fwrite() буфер - это указатель на информацию, записываемую в файл. Длина каждого элемента в байтах определяется в число_байт. Аргумент объем определяет, сколько элементов (каждый длиной число_байт) будет прочитано или записано. Наконец, fp - это файловый указатель на ранее открытый поток.

Функция fread() возвращает число прочитанных элементов. Данное значение может быть меньше, чем объем, если был достигнут конец файла или произошла ошибка. Функция fwrite() возвращает число записанных элементов. Данное значение равно объем, если не возникла ошибка.

Если файл был открыт для двоичных данных, то fread() и fwrite() могут читать и писать любой тип информации. Например, следующая программа записывает float в файл:

/* запись вещественных чисел в файл */
#include <stdio.h>
int main(void)
{
FILE *fp;
char f = ‘s’;
if((fp=fopen("test.txt", "wb"))==NULL)
{

printf("Cannot open file.");

}
fwrite(&f, sizeof (char), 1, fp);
fclose (fp);
return 0;
}

Как иллюстрирует данная программа, буфер может быть (а чаще всего это так и есть) простой переменной.

Одно из наиболее полезных применений fread() и fwrite() - это чтение и запись блоков данных типа массивов или структур. Например, следующий фрагмент записывает содержимое массива вещественных чисел balance в файл balance, используя один оператор fwrite(). Далее она читает мас¬сив, используя один оператор fread(), и выводит его содержимое.

#include <stdio.h>

#include <conio.h>

void main(void)

{

register int i;

FILE *fp;

float balance[100];

 

/* открытие на запись */

if((fp=fopen("balance.txt", "wb"))==NULL) {

printf("Cannot open file.");

}

for(i=0; i<100; i++) balance[i] = (float) i;

 

/* сохранение за раз всего массива balance */

fwrite(balance, sizeof balance, 1, fp) ;

fclose(fp);

 

 

/* открытие для чтения */

if((fp=fopen("balance.txt","rb"))==NULL) {

printf("cannot open file");

 

}

 

/* чтение за раз всего массива balance */

fread(balance, sizeof balance, 1, fp);

 

/* вывод содержимого массива */

for(i=0; i<100; i++) printf("%0.2f ", balance [i]);

fclose(fp);

 

_getch();

}

 

 

Использование fread() и fwrite() для чтения или записи сложных данных более эффективно, чем использование повторяющихся вызовов getc() и putc().