2017-01-24 8 views
0

非常に類似した質問はすでにここに頼まれた: Writing to both terminal and file c++C++は - コンソール出力を維持しながらファイルに標準出力/標準エラー出力を複製

をしかし、良い答えなし。すべての答えは、カスタムストリームを使用するか、std :: coutを複製することを提案しています。しかし、私はstdout/stderrの動作が必要です。

欲しいもの:stdout/stderrへの書き込みごとに、これをコンソールに表示して、ファイルにリダイレクトします。

私はファイルへの書き込みをパイプに標準出力をリダイレクトについて、そこから考えて、コンソールました - この答えにhttps://stackoverflow.com/a/956269/2308106

を拡大するには、これに任意のより良い方法はありますか?

EDIT1:なぜカスタムストリームではなく、stdout/stderrであるのですか?

私は変更できず、自分のプロセス内でホストされている(第三者)コードを呼び出しています。だから私はカスタムストリームを使用することはできません(呼び出されたコードはすでにstderr/stdoutに書き込まれています)。

EDIT2:いくつかの問題しかし

HANDLE hPipe = ::CreateNamedPipe(TEXT("\\\\.\\pipe\\StdErrPipe"), 
    PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE, 
    PIPE_TYPE_BYTE, 
    //single instance 
    1, 
    //default buffer sizes 
    0, 
    0, 
    0, 
    NULL); 

if (hPipe == INVALID_HANDLE_VALUE) 
{ 
    //Error out 
} 

bool fConnected = ConnectNamedPipe(hPipe, NULL) ? 
    TRUE : (GetLastError() == ERROR_PIPE_CONNECTED); 

if (!fConnected) 
{ 
    //Error out 
} 

int fd = _open_osfhandle(reinterpret_cast<intptr_t>(hPipe), _O_APPEND | /*_O_WTEXT*/_O_TEXT); 

if (dup2(fd, 2) == -1) 
{ 
    //Error out 
} 

がまだある - 私は受信パイプのもう一方の端から通り:私は私の実装(Windows)を試してみましたJVOからの提案に基づき

rubish(私は最初に何かをdirrectly送信しようとする - それは素晴らしいですが、stderrがリダイレクトされ、それに書き込むと、パイプは同じnonininble文字を何度も受け取ります)

+0

リンク先の最初の質問では、上位回答が2つの出力を行う単純な関数であることに気づくでしょうか? 1つはファイルに、もう1つは 'std :: cout'ですか?あなたはそれを同じように解決できませんか?呼び出す関数を作成すると、ファイルと 'stdout'の両方に書き出しますか? –

+0

カスタムストリームが悪いのはなぜですか?既存のソリューションで何が問題になっていますか? 「ostream」の一部ではないので、あなたは好きではないでしょうか? – AndyG

+0

また、あなたは 'stdout'や' stderr'に書き込む必要性について詳しく説明できますか?あなたは変更できないC関数をいくつか呼びますか?あなたが解決しようとしている*実際の*と*元の*問題は何ですか? [XY問題について読む](http://xyproblem.info/)と、それがあなたの質問にどのように関係するかを考えてください。 –

答えて

1

あなたはポインタを置き換えることにより、 'ハイジャック' stdoutとstderrことができます。 stdoutとstderrはFILE *以上である。最初にパイプのペアを開いてから、fdopen()を使って新しいFILE *を作成し、パイプの送信側でassiocatedしてからstdoutを新しいFILEに渡すことをお勧めします。パイプの受信側を使用して、「古い」標準出力に書き込まれたものを抽出します。

擬似コード:

int fd[2]; 
FILE *old_stdout, *new_stdout; 

pipe(fd); 
new_stdout = fdopen(fd[1], "w"); 
old_stdout = stdout; 
stdout = new_stdout; 

、あなたはFDから読み込まれ、すべてが[0]ファイルに書き込むことができ、old_stdoutなど

+0

これまでのベストアンサー!あなたはおそらくWindowsの名前付きパイプでこの作業を行う方法を知っていますか? (私の質問の編集に関して) – Jan

+0

申し訳ありません、私のWindowsの知識はかなり限られています – JvO

1

cout。ワン(不完全)の例では、次のようになります。

#include <fstream> 
#include <iostream> 


template<class CharT, class Traits = std::char_traits<CharT> > 
struct teestream : std::basic_streambuf<CharT, Traits> { 

private: 
    std::basic_streambuf<CharT, Traits>* m_rdbuf1; 
    std::basic_streambuf<CharT, Traits>* m_rdbuf2; 

public: 
    teestream(std::basic_streambuf<CharT, Traits>* rdbuf1, std::basic_streambuf<CharT, Traits>* rdbuf2) 
     :m_rdbuf1(rdbuf1) 
     ,m_rdbuf2(rdbuf2) 
    {} 

    ~teestream() { 
     m_rdbuf1->pubsync(); 
     m_rdbuf2->pubsync(); 
    } 

protected: 
    int_type overflow(int_type ch = Traits::eof()) override 
    { 
     int_type result = m_rdbuf1->sputc(ch); 
     if (result != Traits::eof()) 
     { 
      result = m_rdbuf2->sputc(ch); 
     } 
     return result; 
    } 

    virtual int sync() override 
    { 
     int result = m_rdbuf1->pubsync(); 
     if (result == 0) 
     { 
      result = m_rdbuf2->pubsync(); 
     } 
     return result; 
    } 

}; 

typedef teestream<char, std::char_traits<char>> basic_teestream; 

int main() 
{ 
    std::ofstream fout("out.txt"); 
    std::streambuf *foutbuf = fout.rdbuf();   //Get streambuf for output stream 
    std::streambuf *coutbuf = std::cout.rdbuf(); //Get streambuf for cout 

    std::streambuf *teebuf = new basic_teestream(coutbuf, foutbuf); //create new teebuf 

    std::cout.rdbuf(teebuf);//Redirect cout 

    std::cout << "hello" << std::endl; 

    std::cout.rdbuf(coutbuf); //Restore cout 
    delete teebuf; //Destroy teebuf 
} 

あなたはcoutで使用するstreambufは、ストリームバッファそのものだけでなく、ofstreamののストリームバッファを制御で置き換えられ、ここで見ることができるように。

コードには多くの欠陥があり、不完全ですが、そのアイデアを得るべきです。

出典:
https://stackoverflow.com/a/10151286/4181011
How can I compose output streams, so output goes multiple places at once?
http://en.cppreference.com/w/cpp/io/basic_streambuf/pubsync
Implementing std::basic_streambuf subclass for manipulating input

+0

コードをありがとう。しかし、私は** stdout/stderr **を複製する必要があるので、呼び出されたコードを変更することはできません - まさにこれらの – Jan

+0

@Jan Oh。私はあなたのアップデートをキャッチしなかった、申し訳ありません。 –

+0

@SimonKraemer、私はvs2015であなたのコードを試しました、それはファイルにのみ書きますが、コンソールは書きません。 – Robin

関連する問題