如何从C++程序中打开自定义I/O流?

如何从C++程序中打开自定义I/O流?,c++,io,stream,posix,file-descriptor,C++,Io,Stream,Posix,File Descriptor,众所周知,有三个默认I/O流映射到标准库中的预定义对象: 0:std::istream std::cin 1:std::ostream std::cout 2:std::ostream std::cerr和std::ostream std::clog 但是,您可以从bash脚本中创建额外的流3、4、 所以,您能用描述符3创建一个额外的输出流并将其绑定到std::ostream自定义对象吗?如果是,怎么做?std::ofstream没有做到这一点,因为它会创建一个名为3的文件,而这不是我想要的 编

众所周知,有三个默认I/O流映射到标准库中的预定义对象:

0:std::istream std::cin 1:std::ostream std::cout 2:std::ostream std::cerr和std::ostream std::clog 但是,您可以从bash脚本中创建额外的流3、4、

所以,您能用描述符3创建一个额外的输出流并将其绑定到std::ostream自定义对象吗?如果是,怎么做?std::ofstream没有做到这一点,因为它会创建一个名为3的文件,而这不是我想要的


编辑:它不必是便携式的。如果它在POSIX上工作就足够了。

如果您需要程序的可移植性,则不可能。C++ 11标准没有指定统一的方式。

但是,您可以定义自己的输出流缓冲区,该缓冲区覆盖溢出和xsputn虚拟函数,并使用系统特定的API使用指定的描述符将每个字符或字符序列写入流

大致如下:

class my_ostream_buf : public std::streambuf
{

public:

    my_ostream_buf(int fd) : _fd(fd) { }

protected:

    virtual int_type overflow (int_type c)
    {
        if (c != EOF)
        {
            char ch = c;
            if (write(_fd, &ch, 1) != 1)
            {
                return EOF;
            }
        }

        return c;
    }

    // This is not strictly necessary, but performance is better if you
    // write a sequence of characters all at once rather than writing
    // each individual character through a separate system call.
    virtual std::streamsize xsputn(const char* s, std::streamsize num)
    {
        return write(_fd, s, num);
    }

private:

    int _fd = 0;    

};
以下是您将如何使用它:

using namespace std;

int main()
{
    int fd = ...; // Any file descriptor
    my_ostream_buf buf(fd);

    ostream os(&buf); // Take care of the lifetime of `buf` here, or create your
                      // own class that derives from ostream and encapsulates an
                      // object of type my_ostream_buf

    os << "Hello" << endl;
}

如果你需要你的程序是可移植的,这是不可能的。C++ 11标准没有指定统一的方式。

但是,您可以定义自己的输出流缓冲区,该缓冲区覆盖溢出和xsputn虚拟函数,并使用系统特定的API使用指定的描述符将每个字符或字符序列写入流

大致如下:

class my_ostream_buf : public std::streambuf
{

public:

    my_ostream_buf(int fd) : _fd(fd) { }

protected:

    virtual int_type overflow (int_type c)
    {
        if (c != EOF)
        {
            char ch = c;
            if (write(_fd, &ch, 1) != 1)
            {
                return EOF;
            }
        }

        return c;
    }

    // This is not strictly necessary, but performance is better if you
    // write a sequence of characters all at once rather than writing
    // each individual character through a separate system call.
    virtual std::streamsize xsputn(const char* s, std::streamsize num)
    {
        return write(_fd, s, num);
    }

private:

    int _fd = 0;    

};
以下是您将如何使用它:

using namespace std;

int main()
{
    int fd = ...; // Any file descriptor
    my_ostream_buf buf(fd);

    ostream os(&buf); // Take care of the lifetime of `buf` here, or create your
                      // own class that derives from ostream and encapsulates an
                      // object of type my_ostream_buf

    os << "Hello" << endl;
}

标准中对此没有任何规定。以良好的状态 在IOStream的实现中,应该有一些额外的, std::filebuf的特定于实现的构造函数 取一个系统文件描述符,其类型取决于 系统,并从中创建一个filebuf。如果没有,你就得 创建自己的streambuf。这可能或多或少有点困难, 取决于你需要什么:如果你只需要一个简单的, 单向流读取或写入,但不能同时读取或写入,无 支持搜索,输入时无代码翻译,非常方便 相对简单。但你仍然必须熟悉 系统级请求,如读或写。如果你想 支持filebuf所做的一切,它比 复杂

编辑: 我只是想加一个例子。既然你提到bash, 我想:

class FdStreambuf : public std::streambuf
{
    int myFd;
    char buffer[1024];

    bool writeBuffer()
    {
        int len = pptr() - pbase();
        return len == 0 || write( myFd, pptr(), len ) == len;
    }

protected:
    int overflow( int ch )
    {
        int results = ch == traits::eof() ? 0 : ch;
        if ( pbase() != NULL ) {
            if ( ! writeBuffer() ) {
                results = traits::eof();
            }
        }
        setp( buffer, buffer + sizeof( buffer ) );
        sputc( ch );
        return ch;
    }

    int sync()
    {
        return writeBuffer() ? 0 : -1;
    }

public:
    FdStreambuf( int fd ) : myFd( fd ) {}
    int close()
    {
        sync();
        return ::close( myFd );
    }
};

class FdOStream : private FdStreambuf, public std::ostream
{
public:
    FdOStream( int fd )
        : FdStreambuf( fd )
        , std::ostream( this )
    {
    }
    void close()
    {
        if ( FdStreambuf::close() != 0 ) {
            setstate( std::ios_base::badbit );
        }
    }
};
我认为这是所有必要的,但有可能我
忘记了什么。

标准中对此没有任何规定。以良好的状态 在IOStream的实现中,应该有一些额外的, std::filebuf的特定于实现的构造函数 取一个系统文件描述符,其类型取决于 系统,并从中创建一个filebuf。如果没有,你就得 创建自己的streambuf。这可能或多或少有点困难, 取决于你需要什么:如果你只需要一个简单的, 单向流读取或写入,但不能同时读取或写入,无 支持搜索,输入时无代码翻译,非常方便 相对简单。但你仍然必须熟悉 系统级请求,如读或写。如果你想 支持filebuf所做的一切,它比 复杂

编辑: 我只是想加一个例子。既然你提到bash, 我想:

class FdStreambuf : public std::streambuf
{
    int myFd;
    char buffer[1024];

    bool writeBuffer()
    {
        int len = pptr() - pbase();
        return len == 0 || write( myFd, pptr(), len ) == len;
    }

protected:
    int overflow( int ch )
    {
        int results = ch == traits::eof() ? 0 : ch;
        if ( pbase() != NULL ) {
            if ( ! writeBuffer() ) {
                results = traits::eof();
            }
        }
        setp( buffer, buffer + sizeof( buffer ) );
        sputc( ch );
        return ch;
    }

    int sync()
    {
        return writeBuffer() ? 0 : -1;
    }

public:
    FdStreambuf( int fd ) : myFd( fd ) {}
    int close()
    {
        sync();
        return ::close( myFd );
    }
};

class FdOStream : private FdStreambuf, public std::ostream
{
public:
    FdOStream( int fd )
        : FdStreambuf( fd )
        , std::ostream( this )
    {
    }
    void close()
    {
        if ( FdStreambuf::close() != 0 ) {
            setstate( std::ios_base::badbit );
        }
    }
};
我认为这是所有必要的,但有可能我 忘了什么。

我把“和”的答案结合起来,这就是我得到的答案,以防有人需要它

溪流 我结合了“和”的答案,这是我得到的,以防有人需要

溪流
或者重写下溢和写入,因为他提到了一个额外的输出流。您并不真正需要xsgetn。我想加一点缓冲,这也不难。@JamesKanze:是的,缓冲会更好。我只是尽量让它简单。感谢示例实现,我将试一试。请看我的编辑,它不必在POSIX linux和mac之外进行移植,实际上。。。。我的_ostream_buf不应该公开继承std::streambuf吗?或者我错过了什么吗?@bitmask:好的,那么这个简单化的版本应该可以工作了。请记住,它不做任何缓冲。如果您需要缓冲,请查看James Kanze的示例。或者重写underflow并写入,因为他提到了额外的输出流。您并不真正需要xsgetn。我想加一点缓冲,这也不难。@JamesKanze:是的,缓冲会更好。我只是尽量让它简单。感谢示例实现,我将试一试。请看我的编辑,它不必在POSIX linux和mac之外进行移植,实际上。。。。我的_ostream_buf不应该公开继承std::streambuf吗?或者我错过了什么吗?@bitmask:好的,那么这个简单化的版本应该可以工作了。请记住,它不做任何缓冲。如果您需要缓冲,请查看James Kanze的示例。您是对的,ostream包装器可能很方便。怎样
无论如何,FdStreambuf继承可能应该是私有成员,这样包装器就可以是一个模板类,使其更通用。@bitmask您正在将指向streambuf的指针传递到istream的构造函数中。我希望streambuf在istream得到它之前被构造。基类是在成员之前按从左到右的顺序构造的,所以我在从istrea继承之前从streambuf私下继承。看见唯一的问题是,这涉及到不必要的内存分配,但是呃,你是对的,ostream包装器可能很方便。但是,FdStreambuf继承可能应该是一个私有成员,因此包装器可以是一个模板类,使其更通用。@位掩码您正在将指向streambuf的指针传递到istream的构造函数中。我希望streambuf在istream得到它之前被构造。基类是在成员之前按从左到右的顺序构造的,所以我在从istrea继承之前从streambuf私下继承。看见唯一的问题是,有一个不必要的内存分配涉及,但嗯。这对我工作!util::FdStreamBuf WritePipeBuf pipefd;std::ostream ChildDebug&writepebuf;这对我有用!util::FdStreamBuf WritePipeBuf pipefd;std::ostream ChildDebug&writepebuf;儿童调试