Вход в stdin и stdout - PullRequest
       39

Вход в stdin и stdout

1 голос
/ 08 апреля 2019

Есть ли (идеально простой и элегантный) способ регистрации stdin и stdout?

Обратите внимание, что я не намереваюсь перенаправить потоки. Я хочу, чтобы стандартные потоки оставались функциональными для связи с другим программным обеспечением, в то время как также записывает все межпроцессное взаимодействие в некоторый файл.

Ответы [ 2 ]

1 голос
/ 08 апреля 2019

Вариант 1:

Как @ PaulR предлагает , вы можете использовать внешний процесс, такой как tee (в Linux / Mac / Unix), или написать собственный процесс для чтения из stdin в цикле и записи в stdout и другие. файл.

Вариант 2:

Я сделал это много лет назад с std :: basic_ios :: rdbuf для std::cout. Все, что нужно сделать, это определить класс (см. std::filebuf и std::streambuf):

class tee_buf : public std::filebuf {
   public:
     // Not an owing pointer
     tee_buf(std::streambuf * other_stream) 
        : m_other_stream(other_stream) {}
     void swap( tee_buf& rhs );
     // No need to override open/close since we need to manage only the file.
     // The open/close calls don't touch the other_stream.
   protected:
     int_type overflow(int_type c = traits_type::eof()) override;

     // The parent calls this->overflow(), but then still need to call
     // m_other_stream->sync(). This is problematic since m_other_stream
     // gets flushed twice.
     int sync() override;

     pos_type seekoff( off_type off,
                      std::ios_base::seekdir dir,
                      std::ios_base::openmode which) override {
        return pos_type(off_type(-1)); // ???
     }
     pos_type seekpos( pos_type sp,
                      std::ios_base::openmode which) override {
        return pos_type(off_type(-1)); // ???
     }
     ....

Это более эффективно для интенсивного ввода-вывода, так как избегает посредников. Но в большинстве случаев это более простое и предпочтительное решение. Если производительность является проблемой (а в большинстве случаев это не так), то возможно, что оба потоковых буфера совместно используют один буфер памяти. Также возможно использовать асинхронный ввод-вывод для параллельной записи в оба потока.

Использование с утечкой памяти:

std::cout.rdbuf(new tee_buf(std::cout.rdbuf());

Использование без утечки памяти:

Напишите класс RAII, содержащий tee_buf, чтобы сохранить оригинал и установить новый std::cout.rdbuf(). При уничтожении восстановить состояние std::cout.rdbuf(). Сделайте один экземпляр этого класса, который будет выполнять грязную работу при его строительстве и разрушении.

Что касается стиля C stdout: я не верю, что есть способ переопределить его поведение. В лучшем случае можно играть с буферной памятью, но этого недостаточно для получения желаемой функциональности. С stdout единственное, что можно сделать, это использовать tee -подобное решение.

0 голосов
/ 08 апреля 2019

Это должно быть довольно просто сделать с tee. Это позволит вам поддерживать любое существующее перенаправление, а также отправлять stdin / stdout в другое место (в файлы в вашем случае). Это также позволяет избежать внесения каких-либо изменений в существующий код.

...