如何在流程运行时(C ++/Boost.Process)捕获标准输出并同时打印到控制台和文件 [英] How to capture standard out and print to both the console and a file during process runtime (C++/Boost.Process)

查看:417
本文介绍了如何在流程运行时(C ++/Boost.Process)捕获标准输出并同时打印到控制台和文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个使用Boost's C ++ Process库启动子进程的应用程序 ( http://www.highscore.de/boost/process0.5 ) 并使用以下代码将标准从该过程中重定向到文件: boost::process::initializers::bind_stdout(boost::iostreams::file_descriptor_sink去这里)

I am working on an application that starts child processes using Boost's C++ Process library (http://www.highscore.de/boost/process0.5) and redirects the standard out of that process to a file using the below code: boost::process::initializers::bind_stdout(boost::iostreams::file_descriptor_sink goes here )

上述解决方案和代码效果很好.

The above solution and code worked well.

但是,现在,我需要能够将子进程的标准输出到文件和控制台中.

However, now, I need to be able to print the child process's standard out to both a file and the console.

我发现下面的代码似乎可以完成此工作:

I have found the code below which seems that it should do the job:

#include <boost/process.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <iostream>

using namespace boost::process;
using namespace boost::process::initializers;
using namespace boost::iostreams;

int main()
{
    boost::process::pipe p = create_pipe();
    {
        file_descriptor_sink sink(p.sink, close_handle);
        execute(
            run_exe("/bin/echo"),
            set_cmd_line("echo hello"),
            bind_stdout(sink)
        );
    }
    file_descriptor_source source(p.source, close_handle);
    stream<file_descriptor_source> is(source);
    std::string s;
    while (std::getline(is, s))
    {
            std::cout << s << std::endl;
            //will write line by line to file here
    }
}

我已经尝试运行上述代码,并且确实能够将输出打印到控制台和文件中. 但是上述代码存在一个主要问题(至少在我的情况下), while循环(while (std::getline(is, s)))仅在被调用的进程退出后才开始,这意味着一旦进程完成,就立即打印在进程运行过程中累积的所有输出.

I have tried running the above code and indeed I was able to print the output to the console and a file. But there is one major issue with the above code (at least in my case), the while loop (while (std::getline(is, s))) only starts after the invoked process has exited, which means that all the output that was accumulated during the process run is printed at once once the process finishes.

现在, 我需要的是能够在运行时期间从调用的进程中获取输出,并将其输出到控制台和文件来生成(而不是仅在结束).

Now, What I need is to be able to get the output from the invoked process during it's runtime and print it to both the console and the file as it comes (rather than only at the end).

(由于我启动的进程已无法控制,甚至可能需要花费几分钟才能运行,并且当前屏幕控制台一直为空,直到该进程退出).

(Since the processes that I start are out of my control and can take even a few good minutes to run, and currently the screen console is just empty until the process exits).

我去过很多网站,试图找到一个解决方案,并花很多时间在代码上,但是我似乎还不能确定解决方案.

I have went over a lot of websites trying to find a solution for this one, as well as playing a lot with the code, but I can't seem to nail the solution yet.

如何实现? (Boost.Process甚至有可能吗?) 如何在子进程运行时而不是仅在完成时用子进程中的std填充该字符串/流?

How can this be accomplished? (Is it even possible with Boost.Process?) How would I be able to make that string/stream populate with the std out of the child process during it's runtime rather that only when it's finished?

推荐答案

原则上,它应该按您的要求工作.

In principle it should work as you require.

也许您需要冲洗. (尝试使用std::unitbuf).

Perhaps you need to flush. (Try using std::unitbuf).

或者,您可能在Windows上,它不容易支持异步管道.文档描述了create_async_pipe函数:

Alternatively, you might be on Windows, which doesn't support async pipes readily. The docs describe a create_async_pipe function:

bp::pipe create_async_pipe()
{
#if defined(BOOST_WINDOWS_API)
    std::string name = "\\\\.\\pipe\\boost_process_async_io";
    HANDLE handle1 = ::CreateNamedPipeA(name.c_str(), PIPE_ACCESS_INBOUND |
        FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, NULL);
    HANDLE handle2 = ::CreateFileA(name.c_str(), GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    return make_pipe(handle1, handle2);
#elif defined(BOOST_POSIX_API)
    return create_pipe();
#endif
}

因此,这是将所有内容结合在一起的版本,并配有tee设备:

So, here's a version that combines it all, complete with tee device:

#include <boost/process.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <iostream>
#include <fstream>

namespace bp = boost::process;
namespace io = boost::iostreams;
using namespace bp;
using namespace bp::initializers;

bp::pipe create_async_pipe()
{
#if defined(BOOST_WINDOWS_API)
    std::string name = "\\\\.\\pipe\\boost_process_async_io";
    HANDLE handle1 = ::CreateNamedPipeA(name.c_str(), PIPE_ACCESS_INBOUND |
        FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, NULL);
    HANDLE handle2 = ::CreateFileA(name.c_str(), GENERIC_WRITE, 0, NULL,
        OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
    return make_pipe(handle1, handle2);
#elif defined(BOOST_POSIX_API)
    return create_pipe();
#endif
}

int main()
{
    bp::pipe p = create_async_pipe();

    {
        io::file_descriptor_sink sink(p.sink, io::close_handle);
        execute(
            run_exe("/bin/sh"),
            set_cmd_line("sh -c \"echo started; sleep 3 && date\""),
            bind_stdout(sink)
        );
    }

    io::file_descriptor_source source(p.source, io::close_handle);
    io::stream<io::file_descriptor_source> is(source);

    std::cout << "Process is running, let's wait before printing\n";

    system("sleep 1");

    std::ofstream ofile("test.log");
    io::filtering_ostream filt(io::tee(std::cout << std::unitbuf, ofile << std::unitbuf));

    std::string s;
    while (std::getline(is, s))
        filt << s << "\n";
}

选择命令的方式可以验证它是否可以异步方式工作.

The commands have been chosen in such a way that you can verify that it works in async fashion.

如果您希望真正的"异步,也可以使用Boost Asio,有关详细信息,请参阅文档:

If you want "true" asynchrony, you can also employ Boost Asio, see the documentation for details: http://www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_process.tutorial.asynchronous_i_o

这篇关于如何在流程运行时(C ++/Boost.Process)捕获标准输出并同时打印到控制台和文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆