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

时间:2013-02-06 16:33:56

标签: c++ io stream posix file-descriptor

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

  • 0:std::istream std::cin
  • 1:std::ostream std::cout
  • 2:std::ostream std::cerrstd::ostream std::clog

但是,从(例如)bash脚本中,您可以创建其他流(3,4,...)。

那么,您是否可以使用描述符3创建额外的输出流并将其绑定到std::ostream custom对象?如果是这样,怎么样? std::ofstream没有做到这一点,因为它会创建一个名为“3”的文件,这不是我想要的。


编辑:它不必是可移植的。它适用于POSIX。

2 个答案:

答案 0 :(得分:1)

标准中没有提供此功能。好的 执行IOStream,应该有一些额外的, std::filebuf的实现特定构造函数,其中 拿一个系统文件描述符(其类型取决于 系统),并从中创建一个filebuf。如果没有,你必须这样做 创建自己的streambuf。这可能或多或少困难, 取决于你需要什么:如果你只需要一个简单的, 单向流(读或写,但不是两者),没有 支持寻求和输入没有代码翻译,它是 相对简单。 (但你仍然需要熟悉 系统级请求,例如readwrite。)如果您愿意 支持filebuf所做的一切,更重要 复杂。

编辑:

我想我会添加一个例子。既然你说bash, 我想是Unix:

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

(我认为这就是必要的,但我有可能 忘记了什么。)

答案 1 :(得分:1)

我合并了AndyJames的回答,这就是我得到的(如果有人需要的话)

Streams.h

#pragma once

#include <ostream>
#include <unistd.h>

namespace util {
  class StreamWrapperImpl : public std::ostream {
    private:
      typedef std::streambuf* OwnedBufPtr;
      OwnedBufPtr const buf;
    public:
      StreamWrapperImpl(OwnedBufPtr buf)
      : std::ostream(buf)
      , buf(buf)
      {}
      virtual ~StreamWrapperImpl() {
        delete buf;
      }
  };
  template <typename Buf>
  class StreamWrapper : public StreamWrapperImpl {
    public:
      StreamWrapper()
      : StreamWrapperImpl(new Buf())
      {}
      template <typename Arg>
      StreamWrapper(Arg arg) // this could use some perfect forwarding in C++11
      : StreamWrapperImpl(new Buf(arg))
      {}
  };

  class FdStreamBuf : public std::streambuf {
    private:
      int fd;
    protected:
      virtual int_type overflow(int_type c) {
        if (c != EOF) {
          char const ch = c;
          if (write(fd, &ch, 1) != 1)
            return EOF;
        }
        return c;
      }
      virtual std::streamsize xsputn(char const* s, std::streamsize num) {
        return write(fd, s, num);
      }
    public:
      FdStreamBuf(int fd)
      : fd(fd)
      {
      }
  };
}