如何从C++程序中打开自定义I/O流
How to open custom I/O streams from within a C++ program?
众所周知,有三个默认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 custom
对象吗?如果是,如何?std::ofstream
不起作用,因为它会创建一个名为"3"的文件,这不是我想要的。
编辑:它不一定是可移植的。如果它在POSIX上工作就足够了。
如果您需要程序的可移植性,这是不可能的。C++11标准没有规定统一的方法。
但是,您可以定义自己的输出流缓冲区,该缓冲区覆盖overflow()
和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。这可能或多或少是困难的,取决于你需要什么:如果你只需要一个简单的,单向流(读或写,但不能同时读和写),无支持搜索,无需输入代码翻译相对简单。(但你仍然需要熟悉系统级请求,如read
或write
。)如果你想支持filebuf
所做的一切复杂的
编辑:
我只是想加一个例子。既然你提到CCD_ 13,我假设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 );
}
}
};
(我认为这是所有必要的,但我有可能忘记了什么。)
我结合了Andy和James的答案,这就是我得到的(以防有人需要)
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)
{
}
};
}
相关文章:
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- C++自定义比较函数
- 如何比较自定义类的std::变体
- std::设置自定义比较器
- 如何正确实现和访问运算符的各种自定义枚举器
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 自定义先决条件对移动分配运算符有效吗
- 使用VS Code和CMake Tools运行自定义命令
- 如何创建从Maya(或类似程序)到虚幻引擎的自定义数据导出插件
- std::ranges::elements_view,用于自定义类似元组的数据
- 跟随整数索引列表的自定义类迭代器
- 参数化自定义CMake工具链
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 如何在自定义类中启用'auto loops'?
- 使用QJsEngine在Qt中注册自定义类型
- Qt自定义QPush按钮未显示在布局上
- 自定义对象的dlib序列化在gcc中失败
- 自定义创建QFuture
- 如何在QT中的自定义视频小工具t上绘制矩形