Пользовательский класс C ++ cout - вывод в консоль и в файл журнала - PullRequest
8 голосов
/ 10 мая 2011

Я работаю над программой, которая интенсивно использует "cout << strSomething;" записывать информацию в консоль. Мне нужно изменить программу так, чтобы весь вывод консоли шел как в консоль, так и в файл. Хотя я могу изменить «cout <<» в нашем коде, есть несколько больших сторонних библиотек, которые также используют «cout <<»; эти библиотеки не могут быть изменены из-за их лицензий - поэтому изменение всех ссылок на «cout <<» не является решением. Кроме того, использование «wtee.exe» невозможно из-за способа выполнения командных строк. </p>

Я использую Visual Studio 2008. Я видел сообщение на Группы Google: перенаправить cout в файл , который, кажется, делает именно то, что я хочу. Единственная проблема заключается в том, что код не будет компилироваться. Я получаю ошибки C2248 "не удается получить доступ к защищенному члену" при вызовах методов -> overflow () и -> sync ().

Кто-нибудь знает, как получить этот код для компиляции? Или альтернативный способ перенаправления cout на консоль и файл одновременно?

Ответы [ 7 ]

12 голосов
/ 10 мая 2011

boost::iostreams::tee_device создан для этого

#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>

#include <fstream>
#include <iostream>

int
main()
{
    typedef boost::iostreams::tee_device<std::ostream, std::ofstream> Tee;
    typedef boost::iostreams::stream<Tee> TeeStream;

    std::ofstream file( "foo.out" );
    Tee tee( std::cout, file );

    TeeStream both( tee );

    both << "this goes to both std::cout and foo.out" << std::endl;

    return 0;
}

вызова образца:

samm$ ./a.out
this goes to both std::cout and foo.out
samm$ cat foo.out
this goes to both std::cout and foo.out
samm$ 
2 голосов
/ 27 августа 2018

Это легко распространяется на дополнительные потоки.

OstreamFork.hpp - Распределить данные по 2 потокам одновременно

#include <iomanip>
#include <fstream>
#include <iostream>
using namespace std ;

class ostreamFork           // Write same data to two ostreams
{
public:
  ostream& os1 ;
  ostream& os2 ;

  ostreamFork( ostream& os_one , ostream& os_two )
  : os1( os_one ) ,
    os2( os_two )
  {}

 } ;

                          // For data: int, long , ...
 template <class Data>
 ostreamFork& operator<<( ostreamFork& osf , Data d )
 {
   osf.os1 << d ; 
   osf.os2 << d ;
   return osf ;
 }
                        // For manipulators: endl, flush
 ostreamFork& operator<<( ostreamFork& osf , ostream& (*f)(ostream&)  )
 {
   osf.os1 << f ; 
   osf.os2 << f ;
   return osf ;
 }

                            // For setw() , ...
template<class ManipData>
 ostreamFork& operator<<( ostreamFork& osf , ostream& (*f)(ostream&, ManipData )  )
 {
   osf.os1 << f ; 
   osf.os2 << f ;
   return osf ;
 }

TestOstreamFork.cpp:

#include "stdafx.h"
#include <fstream>
  using namespace std ;
#include "ostreamFork.hpp"

int main(int argc, char* argv[])
{
  ofstream file( "test2.txt" ) ;
  ostreamFork osf( file , cout ) ;

  for ( int i = 0 ; i < 10 ; i++ )
  {
    osf << i << setw(10) << " " << 10*i << endl  ;
  }

    return 0 ;
}

Вывод на cout и test2.txt:

0          0
1          10
2          20
3          30
4          40
5          50
6          60
7          70
8          80
9          90
2 голосов
/ 10 мая 2011

если вы в отчаянии:

#define protected public
#include <iostream>
#undef protected

это грубый хак, но обычно это работает.

1 голос
/ 23 июня 2011

Что вы можете сделать, это захватить std::cout.rdbuf() с указателем на std::streambuf, тогда я думаю, что вы сможете записать все выходные данные в std::cout в некоторый файл.

1 голос
/ 10 мая 2011

Звонки sync можно заменить на pubsync. Что касается звонка overflow, я думаю, что это может быть опечатка. как это выглядит, как будто это должен быть вызов sputc.

0 голосов
/ 14 октября 2016

Извините, что разогрел это так поздно, но здесь должно быть решение с перенаправлением cout на teebuffer на основе решения Дитмара Кюля для групп Google.

Использование просто

GetSetLog log("myfile.log");

За время существования объекта "log" все будет записано как в cout / cerr, так и в файл

https://sourceforge.net/p/getset/code/ci/master/tree/GetSet/GetSetLog.hxx

0 голосов
/ 10 мая 2011

вы можете просто использовать класс-обертку для этого, что-то вроде этого

#include <iostream>
#include <fstream>

...

class streamoutput
{
    std::ofstream fileoutput;
    public:
    streamoutput(char*filename){
        fileoutput.open(filename);
    }
    ~streamoutput(){
        fileoutput.close();
    }
    template<class TOut> streamoutput& operator <<(const TOut& data)
    {
        fileoutput << data;
        std::cout << data;
        return this;
    }
};

extern streamoutput cout("logfile.log");

объявить cout таким образом и просто изменить все ваши #include <iostream>, чтобы включить эту обертку (запомнить Cout является внешней переменной, поэтомунужно объявить это в одном из ваших исходных кодов).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...