Файлы и Потоки

Потоки обычно связаны с файлами. Библиотека потоков создает стандартный поток ввода cin, стандартный поток вывода cout и стандартный поток ошибок cerr. Программист может открывать другие файлы и создавать для них потоки.

Инициализация Потоков Вывода

ostream имеет конструкторы:



class ostream {
// ...
ostream(streambuf* s); // связывает с буфером потока
ostream(int fd); // связывание для файла
ostream(int size, char* p); // связывет с вектором
};



Главная работа этих конструкторов - связывать с потоком буфер. streambuf - класс, управляющий буферами; он описывается в #8.6, как и класс filebuf, управляющий streambuf для файла. Класс filebuf является производным от класса streambuf.

Описание стандартных потоков вывода cout и cerr, которое находится в исходных кодах библиотеки потоков ввода/вывода, выглядит так:



// описать подходящее пространство буфера
char cout_buf[BUFSIZE]


// сделать \"filebuf\" для управления этим пространством
// связать его с UNIX\"овским потоком вывода 1 (уже открытым)
filebuf cout_file(1,cout_buf,BUFSIZE);


// сделать ostream, обеспечивая пользовательский интерфейс
ostream cout(&cout_file);


char cerr_buf[1];


// длина 0, то есть, небуферизованный
// UNIX\"овский поток вывода 2 (уже открытый)
filebuf cerr_file()2,cerr_buf,0;


ostream cerr(&cerr_file);

Закрытие Потоков Вывода

Деструктор для ostream сбрасывает буфер с помощью открытого члена функции ostream::flush():



ostream::~ostream()
{
flush(); // сброс
}



Сбросить буфер можно также и явно. Например:

cout.flush();

Открытие Файлов

Точные детали того, как открываются и закрываются файлы, различаются в разных операционных системах и здесь подробно не описываются. Поскольку после включения становятся доступны cin, cout и cerr, во многих (если не во всех) программах не нужно держать код для открытия файлов. Вот, однако, программа, которая открывает два файла, заданные как параметры командной строки, и копирует первый во второй:

#include
  
  
void error(char* s, char* s2)
{
cerr << s << " " << s2 << "\\n";
exit(1);
}
  
  
main(int argc, char* argv[])
{
if (argc != 3) error("неверное число параметров","");
  
  
filebuf f1;
if (f1.open(argv[1],input) == 0)
error("не могу открыть входной файл",argv[1]);
istream from(&f1);
  
  
filebuf f2;
if (f2.open(argv[2],output) == 0)
error("не могу создать выходной файл",argv[2]);
ostream to(&f2);
  
  
char ch;
while (from.get(ch)) to.put(ch);
  
  
if (!from.eof() !! to.bad())
error("случилось нечто странное","");
}

Последовательность действий при создании ostream для именованного файла та же, что используется для стандартных потоков: (1) сначала создается буфер (здесь это делается посредством описания filebuf); (2) затем к нему подсоединяется файл (здесь это делается посредством открытия файла с помощью функции filebuf::open()); и, наконец, (3) создается сам ostream с filebuf в качестве параметра. Потоки ввода обрабатываются аналогично.

Файл может открываться в одной из двух мод:

enum open_mode { input, output };

Действие filebuf::open() возвращает 0, если не может открыть файл в соответствие с требованием. Если пользователь пытается открыть файл, которого не существует для output, он будет создан.

Перед завершением программа проверяет, находятся ли потоки в приемлемом состоянии. При завершении программы открытые файлы неявно закрываются.

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

Копирование Потоков

Есть возможность копировать потоки. Например:

cout = cerr;

В результате этого получаются две переменные, ссылающиеся на один и тот же поток. Главным образом это бывает полезно для того, чтобы сделать стандартное имя вроде cin ссылающимся на что-то другое



Опубликовал admin
23 Мар, Вторник 2004г.



Программирование для чайников.