2009-02-10 2 views
6

Я хочу использовать этот фрагмент от Mr-Edd's iostreams article для печати std :: clog где-нибудь.redirect std :: cout to custom writer

#include <iostream> 
#include <iomanip> 
#include <string> 
#include <sstream> 

int main() 
{ 
    std::ostringstream oss; 

    // Make clog use the buffer from oss 
    std::streambuf *former_buff = 
     std::clog.rdbuf(oss.rdbuf()); 

    std::clog << "This will appear in oss!" << std::flush; 

    std::cout << oss.str() << '\\n'; 

    // Give clog back its previous buffer 
    std::clog.rdbuf(former_buff); 

    return 0; 
} 

так, в основной цикл, я буду делать что-то вроде

while (! oss.eof()) 
{ 
    //add to window text somewhere 
} 

Вот ostringstream docs но у меня возникают проблемы с пониманием, что лучший способ сделать это. У меня есть метод, который отображает текст, я просто хочу назвать его любыми данными в ostringstream.

Что является самым простым/лучшим способом получить что-либо, отправленное в std :: clog, перенаправленным на метод по своему выбору? это как указано выше, и заполнить часть while (не уверен, как), или есть лучший способ, скажем, перегружая некоторый оператор «commit» где-нибудь, который вызывает мой метод? Я хочу быстро и легко, я действительно не хочу начинать определять раковины и такие, которые повышают iostreams, как это делает статья, - это что-то вроде моей головы.

+0

вы могли бы быть более ясно, что ваш вопрос? –

ответ

11

Я призываю вас посмотреть на Boost.IOStreams. Это, кажется, соответствует ваш потребительной случай красиво, и использовать его на удивление прост:

#include <boost/iostreams/concepts.hpp> 
#include <boost/iostreams/stream_buffer.hpp> 
#include <iostream> 

namespace bio = boost::iostreams; 

class MySink : public bio::sink 
{ 
public: 
    std::streamsize write(const char* s, std::streamsize n) 
    { 
     //Do whatever you want with s 
     //... 
     return n; 
    } 
}; 

int main() 
{ 
    bio::stream_buffer<MySink> sb; 
    sb.open(MySink()); 
    std::streambuf * oldbuf = std::clog.rdbuf(&sb); 
    std::clog << "hello, world" << std::endl; 
    std::clog.rdbuf(oldbuf); 
    return 0; 
} 
+0

ваш фрагмент работает в пустом проекте. я скопировал вашу раковину в мой реальный проект и скопировал вашу основную часть в метод init где-то, изменил НИЧЕГО, и у меня появилось несколько страниц ошибок взлома. –

+0

(на этой строке: bio :: stream_buffer sb;) –

+0

Я хотел бы помочь, но вам нужна дополнительная информация об ошибках, которые вы видите. Ограничение размера драконов на комментарии не делает его практичным здесь, поэтому я предлагаю вам опубликовать свой код и ошибки, которые он создает в списке пользователей Boost. http://www.boost.org/community/groups.html#users –

7

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

std::string s = oss.str(); 
if(!s.empty()) { 
    // output s here 
    oss.str(""); // set oss to contain the empty string 
} 

Сообщите мне, если это не то, что вы хотели.

Конечно, лучшее решение - удалить среднего человека и получить новый streambuf, куда бы вы ни отправились действительно хочу его, не нужно пробовать позже. что-то вроде этого (обратите внимание, это делает это для каждого полукокса, но есть много вариантов буферизации в streambufs а):

class outbuf : public std::streambuf { 
public: 
    outbuf() { 
     // no buffering, overflow on every char 
     setp(0, 0); 
    } 

    virtual int_type overflow(int_type c = traits_type::eof()) { 
     // add the char to wherever you want it, for example: 
     // DebugConsole.setText(DebugControl.text() + c); 
     return c; 
    } 
}; 

int main() { 
    // set std::cout to use my custom streambuf 
    outbuf ob; 
    std::streambuf *sb = std::cout.rdbuf(&ob); 

    // do some work here 

    // make sure to restore the original so we don't get a crash on close! 
    std::cout.rdbuf(sb); 
    return 0; 

}

+0

Я не ожидал, что он будет рядом с этим простым, но я попробую. –

0

Если вы просто хотите получить содержимое ostringstream, затем используйте его член str(). Например:

string s = oss.str();  
4

мне нужно, чтобы захватить выходы STD :: COUT и зЬй :: КВЖД от сторонних библиотек и зарегистрировать их с помощью log4cxx, и все еще сохраняя исходные выходы.

Это то, что я придумал. Это довольно просто:

  • я заменить старый буфер на ostream (как станд :: соиЬ) с моим собственным классом, так что я получаю доступ к тому, что когда-либо написано на ней.

  • Я также создаю новый объект std :: ostream со старым буфером, чтобы я мог продолжать выводить вывод на мою консоль, кроме отправки его в мой регистратор. Который я нахожу полезным.

Код:

class intercept_stream : public std::streambuf{ 
public: 
    intercept_stream(std::ostream& stream, char const* logger): 
     _logger(log4cxx::Logger::getLogger(logger)), 
     _orgstream(stream), 
     _newstream(NULL) 
    { 
     //Swap the the old buffer in ostream with this buffer. 
     _orgbuf=_orgstream.rdbuf(this); 
     //Create a new ostream that we set the old buffer in 
     boost::scoped_ptr<std::ostream> os(new std::ostream(_orgbuf)); 
     _newstream.swap(os); 
    } 
    ~intercept_stream(){ 
     _orgstream.rdbuf(_orgbuf);//Restore old buffer 
    } 
protected: 
    virtual streamsize xsputn(const char *msg, streamsize count){ 
     //Output to new stream with old buffer (to e.g. screen [std::cout]) 
     _newstream->write(msg, count); 
     //Output to log4cxx logger 
     std::string s(msg,count); 
     if (_logger->isInfoEnabled()) { 
      _logger->forcedLog(::log4cxx::Level::getInfo(), s, LOG4CXX_LOCATION); 
     } 
     return count; 
    } 
private: 
    log4cxx::LoggerPtr _logger; 
    std::streambuf* _orgbuf; 
    std::ostream&  _orgstream; 
    boost::scoped_ptr<std::ostream> _newstream; 
}; 

Затем, чтобы использовать его:

std::cout << "This will just go to my console"<<std::endl; 
intercept_stream* intercepter = new intercept_stream(std::cout, "cout"); 
std::cout << "This will end up in both console and my log4cxx logfile, yay!" << std::endl; 
+1

Мог вывести некоторую производительность, переместив std :: string внутри проверки isInfoEnabled. –

+0

Это отлично работает! Я только изменил intercept_stream, чтобы взять std :: string вместо char const *, поскольку getLogger берет строку и перемещает строчную конструкцию внутри проверки isInfoEnabled по предложению Райса Улериха. – Fred

1

Для log4cxx примера необходимо переопределить переполнение() и синхронизации() в противном случае badbit всегда устанавливается после первого поток получен.

См: http://groups.google.com/group/comp.lang.c++.moderated/browse_thread/thread/fd9d973282e0a402/a872eaedb142debc

InterceptStream::int_type InterceptStream::overflow(int_type c) 
{ 
    if(!traits_type::eq_int_type(c, traits_type::eof())) 
    { 
     char_type const t = traits_type::to_char_type(c); 
     this->xsputn(&t, 1); 
    } 
    return !traits_type::eof(); 
} 

int InterceptStream::sync() 
{ 
    return 0; 
} 
Смежные вопросы