Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс ПЯВУ 2 сем / Лекции 2 сем / Л№27.Файлы / Лекция №24. Файловая система..odt
Скачиваний:
12
Добавлен:
17.04.2015
Размер:
42.28 Кб
Скачать

17. Функции fprinf() и fscanf()

Кроме основных функций ввода/вывода, о которых шла речь, в системе ввода/вывода языка С также имеются функции fprintf() и fscanf(). Эти две функции, за исключением того, что предназначены для работы с файлами, ведут себя точно так же, как и printf() и scanf(). Прототипы функций fprintf() и fscanf() следующие:

int fprintf(FILE *уф, const char *управляющая_строка, ...);

int fscanf(FILE *уф, const char *управляющая_строка, ...);

где уф — указатель файла, возвращаемый в результате вызова fopen(). Операции ввода/вывода функции fprintf() и fscanf() выполняют с тем файлом, на который указывает уф.

В качестве примера предлагается рассмотреть следующую программу, которая читает с клавиатуры строку и целое значение, а затем записывает их в файл на диске; имя этого файла — TEST. После этого программа читает этот файл и вы-водит информацию на экран. После запуска программы проверьте, каким полу-чится файл TEST. Как вы и увидите, в нем будет вполне удобочитаемый текст.

/* пример использования fscanf() и fprintf() */

#include <stdio.h>

#include <io.h>

#include <stdlib.h>

int main(void)

{

FILE *fp;

char s[80];

int t;

if((fp=fopen("test", "w")) == NULL) {

printf("Ошибка открытия файла.\n");

exit(1);

}

printf("Введите строку и число: ");

fscanf(stdin, "%s%d", s, &t); /* читать с клавиатуры */

fprintf(fp, "%s %d", s, t); /* писать в файл */

fclose(fp);

if((fp=fopen("test","r")) == NULL) {

printf("Ошибка при открытии файла.\n");

exit(1);

}

fscanf(fp, "%s%d", s, &t); /* чтение из файла */

fprintf(stdout, "%s %d", s, t); /* вывод на экран */

return 0;

}

Маленькое предупреждение. Хотя читать разносортные данные из файлов на дисках и писать их в файлы, расположенные также на дисках, часто легче всего именно с помошью функций fprintf() и fscanf(), но это не всегда самый эффективный способ выполнения операций чтения и записи. Так как данные в формате ASCII записываются так, как они должны появиться на экране (а не в двоичном виде), то каждый вызов этих функций сопряжен с определенными накладными расходами. Поэтому, если надо заботиться о размере файла или скорости, то, скорее всего, придется использовать fread() и fwrite().

18. Стандартные потоки

Что касается файловой системы языка С, то в начале выполнения программы автоматически открываются три потока. Это stdin (стандартный поток ввода), stdout (стандартный поток вывода) и stderr (стандартный поток ошибок). Обычно эти потоки направляются к консоли, но в средах, которые поддерживают перенаправление ввода/вывода, они могут быть перенаправлены операционной системой на другое устройство. (Перенаправление ввода/вывода поддерживается, например, такими операционными системами, как Windows, DOS, UNIX и OS/2.)

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

int putchar(char c)

{

return putc(c, stdout);

}

Вообще говоря, stdin используется для считывания с консоли, a stdout и stderr — для записи на консоль.

В роли указателей файлов потоки stdin, stdout и stderr можно применять в любой функции, где используется переменная типа FILE *. Например, для ввода строки с консоли можно написать примерно такой вызов fgets():

char str[255];

fgets(str, 80, stdin);

И действительно, такое применение fgets() может оказаться достаточно полезным. Как уже говорилось в этой книге, при использовании gets() не исключена возможность, что массив, который используется для приема вводимых пользователем символов, будет переполнен. Это возможно потому, что gets() не проводит проверку на отсутствие нарушения границ. Полезной альтернативой gets() является функция fgets() с аргументом stdin, так как эта функция может ограничивать число читаемых символов и таким образом не допустить переполнения массива. Единственная проблема, связанная с fgets(), состоит в том, что она не удаляет символ новой строки (в то время как gets() удаляет!), поэтому его приходится удалять "вручную", как показано в следующей программе:

#include <stdio.h>

#include <string.h>

int main(void)

{

char str[80];

int i;

printf("Введите строку: ");

fgets(str, 10, stdin);

/* удалить символ новой строки, если он есть */

i = strlen(str)-1;

if(str[i]=='\n') str[i] = '\0';

printf("Это Ваша строка: %s", str);

return 0;

}

He забывайте, что stdin, stdout и stderr — это не переменные в обычном смысле, и им нельзя присваивать значение с помощью fopen(). Кроме того, именно потому, что в начале работы программы эти указатели файлов создаются автоматически, в конце работы они и закрываются автоматически. Так что и не пытайтесь самостоятельно их закрыть.

Связь с консольным вводом / выводом

В языке С консольный и файловый ввод/вывод не слишком отличаются друг от друга. Функции консольного ввода/вывода, описанные в главе 8, на самом деле направляют результаты своих операций на один из потоков — stdin или stdout, и по сути, каждая из них является специальной версией соответствующей файловой функции. Функции консольного ввода/вывода для того и существуют, чтобы было удобно именно программисту.

Как говорилось в предыдущем разделе, ввод/вывод на консоль можно выполнять с помощью любой файловой функции языка С. Однако для вас может быть сюрпризом, что, оказывается, операции ввода/вывода на дисковых файлах можно выполнять с помощью функции консольного ввода/вывода, например, printf()! Дело в том, что все функции консольного ввода/вывода, о которых говорилось в главе 8, выполняют свои операции с потоками stdin и stdout. В средах, поддерживающих перенаправление ввода/вывода, это равносильно тому, что stdin или stdout могут быть перенаправлены на устройство, отличное от клавиатуры или экрана. Проанализируйте, например, следующую программу:

#include <stdio.h>

int main(void)

{

char str[80];

printf("Введите строку: ");

gets(str);

printf(str);

return 0;

}

Предположим, что эта программа называется TEST. При ее нормальном выполнении на экран выводится подсказка, затем читается строка, введенная с клавиатуры, и, наконец, эта строка выводится на экран. Однако в средах, в которых поддерживается перенаправление ввода/вывода, один из потоков stdin или stdout (или оба одновременно) можно перенаправить в файл. Например, в среде DOS или Windows следующий запуск TEST

TEST > OUTPUT

приводит к тому, что вывод этой программы будет записан в файл по имени OUTPUT. А следующий запуск TEST

TEST < INPUT > OUTPUT

направляет поток stdin в файл по имени INPUT, а поток стандартного вывода — в файл по имени OUTPUT.

Когда С-программа завершается, то все перенаправленные потоки возвращаются в состояния, которые были установлены по умолчанию.

Перенаправление стандартных потоков: функция freopen()

Для перенаправления стандартных потоков можно воспользоваться функцией freopen(). Эта функция связывает имеющийся поток с новым файлом. Так что она вполне может связать с новым файлом и стандартный поток. Вот прототип этой функции:

FILE *freopen(const char *имя_файла, const char *режим, FILE *поток);

где имя_файла — это указатель на имя файла, который требуется связать с потоком, на который указывает указатель поток. Файл открывается в режиме режим; этот параметр может принимать те же значения, что и соответствующий параметр функции fopen(). Если функция freopen() выполнилась успешно, то она возвращает поток, а если встретились ошибки, — то NULL.

В следующей программе показано использование функции freopen() для перенаправления стандартного потока вывода stdout в файл с именем OUTPUT.

#include <stdio.h>

int main(void)

{

char str[80];

freopen("OUTPUT", "w", stdout);

printf("Введите строку: ");

gets(str);

printf(str);

return 0;

}

Вообще говоря, перенаправление стандартных потоков с помощью freopen() в некоторых случаях может быть полезно, например, при отладке. Однако выполнение дисковых операций ввода/вывода на перенаправленных потоках stdin и stdout не настолько эффективно, как использование таких функций, как fread() или fwrite().

Вопросы для самопроверки.