// output console and file simutainiouslyclassRedirectStdIO{public:RedirectStdIO(stringstr,boolneedStd=true):path(str),need_std(needStd){std_out=dup(fileno(stdout));// 保存下来,方便后续找回std_outstd_err=dup(fileno(stderr));if(!direct2file(path))std::cerr<<"Can not redirect output to file "<<path<<std::endl;}booldirect2file(stringstr){if(str.empty())returnfalse;fp=freopen(str.c_str(),"w",stdout);dup2(fileno(stdout),fileno(stderr));// 重定向return(fp!=nullptr);}voidback2stdout(){fflush(fp);dup2(std_out,fileno(stdout));// cout重回screendup2(std_err,fileno(stderr));close(std_out);close(std_err);// cout lines in file path to stdoutstringline;ifstreammyfile(path);if(myfile.is_open()){while(getline(myfile,line)){cout<<line<<'\n';}myfile.close();}cout.flush();need_std=false;}~RedirectStdIO(){if(need_std)back2stdout();if(fp)fflush(fp);if(fp)fclose(fp);}private:FILE*fp=nullptr;intstd_out,std_err;boolneed_std;stringpath;};
#include<iostream>
#include<streambuf>
#include<fstream>//------------------------------------------------------------------------------template<classcharT,classtraits=std::char_traits<charT>>classbasic_teebuf:publicstd::basic_streambuf<charT,traits>{public:typedefcharTchar_type;typedeftypenametraits::int_typeint_type;typedeftypenametraits::pos_typepos_type;typedeftypenametraits::off_typeoff_type;typedeftraitstraits_type;typedefstd::basic_streambuf<charT,traits>streambuf_type;private:streambuf_type*m_sbuf1;streambuf_type*m_sbuf2;char_type*m_buffer;enum{BUFFER_SIZE=4096/sizeof(char_type)};public:basic_teebuf(streambuf_type*sbuf1,streambuf_type*sbuf2):m_sbuf1(sbuf1),m_sbuf2(sbuf2),m_buffer(newchar_type[BUFFER_SIZE]){setp(m_buffer,m_buffer+BUFFER_SIZE);}//constructor~basic_teebuf(){this->pubsync();delete[]m_buffer;}//destructorprotected:virtualint_typeoverflow(int_typec=traits_type::eof()){// empty our buffer into m_sbuf1 and m_sbuf2std::streamsizen=static_cast<std::streamsize>(this->pptr()-this->pbase());std::streamsizesize1=m_sbuf1->sputn(this->pbase(),n);std::streamsizesize2=m_sbuf2->sputn(this->pbase(),n);if(size1!=n||size2!=n)returntraits_type::eof();// reset our buffersetp(m_buffer,m_buffer+BUFFER_SIZE);// write the passed character if necessaryif(!traits_type::eq_int_type(c,traits_type::eof())){traits_type::assign(*this->pptr(),traits_type::to_char_type(c));this->pbump(1);}//ifreturntraits_type::not_eof(c);}//overflowvirtualintsync(){// flush our buffer into m_sbuf1 and m_sbuf2int_typec=this->overflow(traits_type::eof());// checking return for eof.if(traits_type::eq_int_type(c,traits_type::eof()))return-1;// flush m_sbuf1 and m_sbuf2if(m_sbuf1->pubsync()==-1||m_sbuf2->pubsync()==-1)return-1;return0;}//sync};//basic_teebuftypedefbasic_teebuf<char>teebuf;typedefbasic_teebuf<wchar_t>wteebuf;//------------------------------------------------------------------------------template<classcharT,classtraits=std::char_traits<charT>>structscoped_basic_streambuf_assignment{typedefstd::basic_ios<charT,traits>stream_type;typedefstd::basic_streambuf<charT,traits>streambuf_type;stream_type&m_s;streambuf_type*m_orig_sb;scoped_basic_streambuf_assignment(stream_type&s,streambuf_type*new_sb):m_s(s){m_orig_sb=m_s.rdbuf(new_sb);}//constructor~scoped_basic_streambuf_assignment(){m_s.rdbuf(m_orig_sb);}//destructor};//scoped_streambuf_assignmenttypedefscoped_basic_streambuf_assignment<char>scoped_streambuf_assignment;typedefscoped_basic_streambuf_assignment<wchar_t>scoped_wstreambuf_assignment;//------------------------------------------------------------------------------intmain(){std::ofstreamfile("data.txt");std::ofstreamfile2("data2.txt");// tbuf will write to both file and coutteebuftbuf(file.rdbuf(),std::cout.rdbuf());// tbuf2 will write to both tbuf and file2teebuftbuf2(file2.rdbuf(),&tbuf);// replace cout's streambuf with tbuf2scoped_streambuf_assignmentssa(std::cout,&tbuf2);std::cout<<"Hello World"<<std::endl;return0;}//main