Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
lab_stream.doc
Скачиваний:
25
Добавлен:
16.02.2016
Размер:
3.85 Mб
Скачать

Параметры функции:

  • stream Указатель на объект типа FILE, который связан с потоком (потоковая переменная).

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

Форматируемые теги должны следовать следующему формату записи:

%[флаги][ширина поля][.точность][длина]спецификатор

 Спецификаторы задают тип выводимых данных и способ из представления. Ниже приведены спецификаторы форматирования потоков ввода/вывода:

Таблица 1. Спецификаторы вывода функции fprintf

Спецификатор

Описание

c

Символ

d или i

Знаковое десятичное число.

e

Экспоненциальная форма записи чисел (мантисса/экспонента) с использованием символаe.

E

Экспоненциальная форма записи чисел (мантисса/экспонента) с использованием символаE.

f

Десятичное значение с плавающей точкой.

g

Используется для обозначения короткого %e или %f

G

Используется для обозначения короткого %E или %f

o

Восьмеричная система счисления

s

Строка символов.

u

Использовать беззнаковое целое десятичное значение.

x

Использовать беззнаковые шестнадцатеричные значения

X

Шестнадцатеричные целые без знака (прописные буквы)

p

Указатель на адрес

n

Запись по указателю, переданному в качестве аргумента, количества символов, записанных на момент появления командной последовательности, содержащей n

%

Вывод символа %

Форматирующие теги могут также содержать флаги, ширину, точность и модификаторы, которые являются необязательными:

Таблица 2. Флаги вывода функции fprintf

Флаг

Описание

-

Выравнивание по левому краю выделенного поля. По умолчанию стоит правостороннее выравнивание в выделенном поле.

+

Использовать знаки плюс или минус для вывода значений. По умолчанию выводится только знак минус, если значение отрицательное.

(space)

Если в строке есть символ пробела, он не игнорируется, а попадает в поток вывода.

#

Используется вместе со спецификаторами o, x или X специфицирующих значение отличное от нуля, 0x или0X. Используется вместе со спецификаторами e, E и f, принудительно  выводит десятичную точку, даже, если у значения нет цифр в дробной части. По умолчанию, если нет цифр в дробной части, десятичная точка не отображается. Используется с a, A, e, E, f, F, g или G результат такой же, как и со спецификаторами е или Е, но нули не удаляются.

0

Левая часть после числа заполняется нулями (0) вместо пробелов, если ширина поля больше числа.

Таблица 3. Ширина вывода для функции fprintf

ширина

Описание

number

Минимальное количество символов для печати. Если значение для печати короче, чем это число, пустые места заполняются пробелами. Значение не обрезается, даже если оно больше number.

*

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

Таблица 4. Точность вывода функции fprintf

.точность

Описание

.number

Для спецификаторов целых чисел d, i, o, u, x, X: указывает минимальное количество цифр. Если значение, короче, чем это число, пустое место заполняется нулями. Значение не обрезается, даже если number меньше, чем длина выводимого объекта.   Для спецификаторов е, Е и F: это количество цифр, которое будет напечатано после десятичной точки. Для спецификаторов g и G это максимальное количество значащих цифр для печати.

 Для спецификатора s - это максимальное количество символов для печати.

Для c этот параметр не имеет значения. При отсутствии этого параметра, точность по умолчанию равна 1.

.*

Точность не указана в строке формата, но в качестве дополнительного аргумента передается целое значение, оно должно предшествовать форматируемому аргументу.

Таблица 5. Длина вывода функции fprintf

длина

Описание

h

short int или unsigned short int (применяется только к целым спецификаторам: i, d, o, u, x иX).

l

long int или unsigned long int в случае применения к целым спецификаторам (i, d, o, u, x и X), а также к широким символам или строкам с широкими символами, для спецификаторов c и s.

L

Long double в случае применения к спецификаторам вещественных типов %e, %E, %f, %F, %g, %G)

В случае успешного вывода функция fprintf возвращает общее число записанных символов. В случае неудачи, возвращается отрицательное число.

Рассмотрим пример форматированного вывода информации в поток

//Листинг 2. Запись данных в поток функцией fprintf

#include <stdio.h>

#include <windows.h>

int main(int argc, _TCHAR* argv[])

{

SetConsoleCP(1251);

SetConsoleOutputCP(1251);

int n, age;

char name[20];

FILE* pFile = fopen ("d:\\myfile.txt","w");

for (n=0 ; n<5 ; n++)

{

puts ("Введите имя: ");

gets (name);

puts ("Введите возраст: ");

scanf("%d", &age);

fflush(stdin);

fprintf (pFile, "%2d. Имя [%-20.20s] Возраст [%-3d]\n",n,name, age);

}

fclose (pFile);

return 0;

}

В приведенном примере для функции fprintf использованы три спецификатора вывода – для вывода порядкового номера %2d (целое число, под вывод отводится 2 позиции), имени %-20.20s (строка, выровненная по левому краю, под вывод отводится минимум 20 позиций, максимально выводится 20 символов) и возраст %-3d (целое число, под вывод отводится 3 позиции, вывод выравнивается по левой границе). В результате в файле получим следующее содержимое:

0. Имя [Иван Иванов ] Возраст [23 ]

1. Имя [Ольга Александрова ] Возраст [19 ]

2. Имя [Петр Петров ] Возраст [38 ]

3. Имя [Мария Сидорова ] Возраст [29 ]

4. Имя [Егор Егоров ] Возраст [46 ]

Для чтения форматированных данных из потока необходимо использовать функцию fscanf.

int fscanf (FILE * stream, char * format_string, …); где stream - потоковая переменная, format_string - строка управления форматом.

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

Спецификация ввода имеет следующий формат:

%[*][ширина][длина]спецификатор 

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

pFile = fopen ("d:\\myfile.txt","r");

while(!feof(pFile))

{ fscanf (pFile, "%2d. Имя [%20s ] Возраст [%d ]\n",&n, name, &age);

printf("Номер: %2d Имя %s Возраст %d\n", n, name, age);

}

Использование функции fscanf для чтения данных сложного формата может приводить к проблемам интрепретации считанных данных, поскольку в качестве разделителя считываемых объектов используются пробел и пробельные символы. Необходимо строго следить за соответствием формата записи (в fprintf) и считывания (в fscanf).

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

size_t fread (void * buffer, size_t size,

size_t count, FILE * fp);

size_t fwrite (const void * buffer, size_t size,

size_t count, FILE * fp);

buffer– указатель на область памяти, в которую будут прочитаны данные из потока (для fread) или из которой будут выводиться данные в поток (для fwrite).

count — счетчик, определяющий, сколько считывается и записывается блоков данных,

size - задает размера блока считываемого/записываемого блока данных.

fp – потоковая переменная, связанная с потоком, из которого/в который читаются/пишутся данные.

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

Вывод с использованием fwrite

Форматированный вывод fprintf

int x=142822;

fwrite(&x, 1, sizeof(int), fp);

double x=142822;

fprintf(fp, “%d”, x);

Содержимое файла после вывода: двоичное

Значение переменной займет в файле 4 байта (по размеру переменной)

Содержимое файла после вывода: тестовое

Значение переменной займет в файле 6 байта (по количеству цифр)

Если необходимо вывести в файл содержимое массива, функция fwrite позволяет обойтись без использования цикла:

Вывод с использованием fwrite

Форматированный вывод fprintf

const int N=10;

double mas[N];

…//инициализация массива

fwrite(mas, N, sizeof(double), fp);

const int N=10;

double mas[N];

…//инициализация массива

for(int i=0; i<N; i++)

fprintf(fp, “mas[%d]=%f”, i,mas[i]);

При выводе (вводе) структурной переменной нет необходимости отдельно записывать (считывать) каждое поле:

Вывод с использованием fwrite

Форматированный вывод fprintf

struct MyStruct

{

int field1;

char field2[40];

double field[3];

} m;

fread(&m, 1, sizeof(MyStruct), fp);

struct MyStruct

{

int field1;

char field2[40];

double field[3];

} m;

fscanf(fp, “%d”, &m.field1);

fscanf(fp, “%s”, m.field2);

for(int i=0; i<3; i++)

fscanf(fp, “%f”, &m.field3[i]);

Еще одно достоинство fwrite/fread перед fscanf/fprintf – в скорости выполнения операций. Функции форматированного ввода-вывода перед непосредственно перемещением данных форматируют в соответствии с заданной стройкой форматов, а это требует дополнительного времени. При использовании fwrite/fread форматирования данных не производится, операции выполняются быстрее.

Язык С++ также поддерживает концепцию объектно-ориентированного ввода-вывода, но потоки здесь представлены в виде объектов классов библиотеки iostream:

ifsteram   - для ввода из файла;

ofsteram   - для вывода в файл;

fsteram     - для обмена с файлом в двух направлениях.

При этом стандартные потоки представлены объектами:

cin – стандартный поток ввода;

cout – стандартный поток вывода;

cerr – стандартный поток приема сообщений об ошибках.

Принцип работы с потоками аналогичен принятому в языке Си - программист создает объект-поток как экземпляр требуемого класса, связывая его с файлом на диске, после чего используя сервисные функции. Для чтения данных их потока можно использовать перегруженную операцию >>, для записи информации в поток используется операция <<. Принципиальное отличие объектно-ориентированного подхода Си++ заключается в том, что весь функционал работы с потоком сосредоточен в методах классов, которые должны вызываться в контексте объекта-потока. В листинге 4 приведен пример обмена данными программы с файлом на языке Си++.

#include <fstream.h>

fstream f; char str[20];

f.open("temp",ios::in|ios::out); //открываем поток на

//чтение и запись

f.write(“Тест”,4); //пишем в поток слово Тест

f.seekg(0); //перемещаем указатель потока в его начало

f>>str; //читаем строку из потока

cout<<str;

Таким образом, эффективное использование потокового ввода-вывода на языке Си++ должно опираться на знание методов и компонентных данных классов-потоков. Как видно из примера, названия методов во многом схожи с названиями функции библиотеки Си и разобраться в их назначении и способах применения будет совсем несложно. Более подробную информацию о потоковых классах языка Си++ можно почерпнуть в [1].

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]