我正在尝试为只读流类提供适当的API。 std :: istream接口有点过于复杂,因为它包含格式化读取,而我只对二进制读取感兴趣(必须处理压缩流)。
我想出了(需要C99 <stdint.h>
):
struct stream
{
virtual uintmax_t size() const = 0;
virtual uintmax_t tell() const = 0;
virtual bool read( char * out, size_t len ) = 0;
virtual bool skip( uintmax_t len ) = 0;
};
我发现很难回答的问题是size()
是否应该成为API的一部分。从磁盘上的文件中读取数据时,我只需使用stat(2)
即可。通过HTTP接收数据时,我只需阅读Content-Length
(RFC 2616)的值......
在图书馆一级这个size()
功能是否安全?或者只应在应用程序级别满足此类要求?
答案 0 :(得分:1)
我不认为应该提供size()
,因为许多支持流的一般概念的东西都无法实现它;如果你确实提供了它 - 在没有哨兵价值或例外的时候 - 你最终会得到一个&#34;胖子&#34;在一个具体流实现上编码和测试的接口和客户端可能会在另一个实现上失败。也可能存在竞争条件,例如:在调用size()
和稍后的read
次尝试之间扩展或截断文件。
我还建议考虑size_t read_nonblocking(char*, size_t)
返回当前可用的字符数。 std::istream
界面是寻找其他成员函数创意的合理位置。
答案 1 :(得分:0)
所以我最终使用了:
struct stream
{
virtual intmax_t size() const { return -1; }
virtual intmax_t tell() const { return -1; }
virtual bool read( char * out, size_t len ) = 0;
virtual bool skip( intmax_t len ) = 0;
};
从技术上讲,stream::skip
可以简单地通过一个虚拟函数定义为对stream::read
的多次调用,但我认为这样更清晰。这导致了一个具体的管道类:
struct pipe_source : public stream
{
pipe_source() {
seekable = true;
std::cin.seekg(0, std::ios::beg);
if (std::cin.fail())
{
seekable = false;
std::cin.clear();
}
}
bool read( char * out, size_t len )
{
std::cin.read( out, len );
return std::cin.good();
}
bool skip( intmax_t len )
{
if( seekable )
std::cin.seekg( len, std::ios::cur );
else
{
while( len-- > 0 )
std::cin.get();
}
return std::cin.good();
}
private:
bool seekable;
};