Шаг 500.
Библиотека STL. Ввод-вывод с использованием потоковых классов. Связывание потоков ввода-вывода. Перенаправление стандартных потоков данных

    На этом шаге мы рассмотрим особенности перенаправления стандартных потоков ввода-вывода.

    В старых реализациях библиотеки 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());


   Замечание. Объект file является локальным и уничтожается в конце блока, что также приводит к уничтожению соответствующего потокового буфера. В этом отношении файловые потоки данных отличаются от "обычных", поскольку они создают свои объекты потоковых буферов во время конструирования и уничтожают их при уничтожении.

    Учитывая это замечание, в приведенном примере дальнейшее использование объекта 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(), попали в восстановленный выходной канал.

    На следующем шаге мы рассмотрим потоки чтения и записи.




Предыдущий шаг Содержание Следующий шаг