На этом шаге мы рассмотрим особенности перенаправления стандартных потоков ввода-вывода.
В старых реализациях библиотеки IOStream глобальные потоки данных cin, cout, cerr и clog были объектами классов istream_withassign и ostream_withassign. Это позволяло перенаправлять потоки данных, присваивая одни потоки другим. Этот механизм был исключен из стандартной библиотеки C++. Тем не менее сама возможность перенаправления потоков данных была сохранена и расширена так, что теперь она может применяться ко всем потокам данных. Перенаправление потока данных осуществляется назначением потокового буфера.
В механизме назначения потоковых буферов перенаправление потоков данных находится под управлением программы, операционная система здесь не участвует. Например, в результате выполнения следующего фрагмента данные, отправленные в поток данных cout, будут передаваться не в стандартный выходной канал, а в файл cout.txt:
std::ofstream file ("cout.txt"); std::cout.rdbuf (file.rdbuf());
Для передачи всей форматной информации между потоками данных можно воспользоваться функцией copyfmt():
std::ofstream file ("cout.txt"); file.copyfmt (std::cout); std::cout.rdbuf (file.rdbuf());
Учитывая это замечание, в приведенном примере дальнейшее использование объекта cout для записи невозможно. Более того, его даже нельзя безопасно уничтожить при завершении программы. По этой причине прежний буфер следует всегда сохранять с последующим восстановлением! В представленном ниже примере это делается в функции redirect():
//--------------------------------------------------------------------------- #include <vcl.h> // Заголовочные файлы для файлового ввода-вывода #include <fstream> #include <iostream> #include <conio.h> //необходимо для getch() #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused using namespace std; std::string ToRus(const std::string &in) { char *buff = new char [in.length()+1]; CharToOem(in.c_str(),buff); std::string out(buff); delete [] buff; return out; } void redirect(ostream&); int main (int argc, char* argv[]) { cout << ToRus("Первая строка") << endl; redirect(cout); cout << ToRus("Последняя строка") << endl; getch(); return 0; } void redirect (ostream& strm) { ofstream file("redirect.txt"); // Сохранение выходного буфера потока streambuf* strm_buffer = strm.rdbuf(); // Перенаправление вывода в файл strm.rdbuf (file.rdbuf()); file << ToRus("Последняя строка в файле") << endl; strm << ToRus("Последняя строка в потоке") << endl; // Восстановление старого выходного буфера strm.rdbuf (strm_buffer); } // Автоматическое закрытие файла и буфера //---------------------------------------------------------------------------
Результат выполнения программы выглядит так:
Рис.1. Результат работы приложения
Содержимое файла redirect.txt:
Последняя строка в файле Последняя строка в потоке
Как видите, данные, записанные в поток данных cout внутри функции redirect(), были переданы в файл (по имени параметра strm), а даииые, записанные в main() после выполнения redirect(), попали в восстановленный выходной канал.
На следующем шаге мы рассмотрим потоки чтения и записи.