我一直在使用std::istream
andostream
作为 C++ 中随机访问二进制 I/O 的多态接口,但它在许多方面似乎都不是最理想的:
- 由于 streampos/streamoff 的限制,64 位搜索是不可移植的并且容易出错;目前使用boost/iostreams/positioning.hpp作为解决方法,但需要警惕
- 缺少诸如截断或扩展文件的操作(ala POSIX
ftruncate
) - 具体实现之间的不一致;例如
stringstream
具有独立的获取/放置位置,而filestream
没有 - 平台实现之间的不一致;例如,寻求通过文件末尾的行为或在错误时使用
failbit
/badbit
- 不需要所有的格式化工具,
stream
甚至可能不需要缓冲streambuf
streambuf
错误报告(即异常与返回错误指示符)在实践中被认为是依赖于实现的
我喜欢Boost.Iostreams Device 概念提供的简化接口,但它是作为函数模板而不是多态类提供的。(有一个device
类,但它不是多态的,只是提供的设备实现不一定使用的实现助手类。)我主要使用大型磁盘文件,但我真的想要多态,所以我可以轻松替换替代实现(例如使用stringstream
而不是fstream
用于单元测试)没有深度模板实例化的所有复杂性和编译时耦合。
有没有人对此有任何标准方法的建议?这似乎是一种常见的情况,所以我不想不必要地发明自己的接口。例如,像 java.nio.FileChannel 这样的东西似乎很理想。
到目前为止,我最好的解决方案是在 Boost.Iostreams 设备上放置一个薄的多态层。例如:
class my_istream
{
public:
virtual std::streampos seek(stream_offset off, std::ios_base::seekdir way) = 0;
virtual std::streamsize read(char* s, std::streamsize n) = 0;
virtual void close() = 0;
};
template <class T>
class boost_istream : public my_istream
{
public:
boost_istream(const T& device) : m_device(device)
{
}
virtual std::streampos seek(stream_offset off, std::ios_base::seekdir way)
{
return boost::iostreams::seek(m_device, off, way);
}
virtual std::streamsize read(char* s, std::streamsize n)
{
return boost::iostreams::read(m_device, s, n);
}
virtual void close()
{
boost::iostreams::close(m_device);
}
private:
T m_device;
};