简体   繁体   English

如何在进程运行时期间捕获标准输出并打印到控制台和文件(C ++ / Boost.Process)

[英]How to capture standard out and print to both the console and a file during process runtime (C++/Boost.Process)

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 ) 我正在开发一个使用Boost的C ++ Process库( http://www.highscore.de/boost/process0.5 )启动子进程的应用程序,并使用以下代码将该进程的标准重定向到一个文件: boost::process::initializers::bind_stdout(boost::iostreams::file_descriptor_sink到这里)

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
    }
}

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. 但是上面的代码存在一个主要问题(至少在我的情况下),while循环( while (std::getline(is, s)) )仅在调用的进程退出后启动,这意味着所有输出过程运行期间累积的数据会在过程结束后立即打印出来。

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. 我已经找了很多网站试图找到这个解决方案,并且在代码中玩了很多,但我似乎无法解决这个问题。

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? (甚至可以使用Boost.Process吗?)如何在运行时期间将该字符串/流填充到子进程的std中,而不是只有在它完成时?

In principle it should work as you require. 原则上它应该按照您的要求工作。

Perhaps you need to flush. 也许你需要冲洗。 (Try using std::unitbuf ). (尝试使用std::unitbuf )。

Alternatively, you might be on Windows, which doesn't support async pipes readily. 或者,您可能在Windows上,它不支持异步管道。 The docs describe a create_async_pipe function: 文档描述了create_async_pipe函数:

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
}

So, here's a version that combines it all, complete with tee device: 所以,这是一个结合了它的版本,完整的tee设备:

#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. 已经选择了这些命令,您可以验证它是否以异步方式工作。

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 如果你想要“真正的”异步,你也可以使用Boost Asio,详见文档: http//www.highscore.de/boost/process0.5/boost_process/tutorial.html#boost_process.tutorial.asynchronous_i_o

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM