这很简单,而且我的手指头,但我认为这些方面的事情会奏效:
template <unsigned BUF_SIZE>
struct Buffer {
char buf_[BUF_SIZE];
int len_;
Buffer () : buf_(), len_(0) {}
int read (int fd) {
int r = read(fd, buf_ + len_, BUF_SIZE - len_);
if (r > 0) len_ += r;
return r;
}
int capacity () const { return BUF_SIZE - len_; }
}
template <unsigned BUF_SIZE>
struct BufferStream {
typedef std::unique_ptr< Buffer<BUF_SIZE> > BufferPtr;
std::vector<BufferPtr> stream_;
BufferStream () : stream_(1, BufferPtr(new Buffer<BUF_SIZE>)) {}
int read (int fd) {
if ((*stream_.rbegin())->capacity() == 0)
stream_.push_back(BufferPtr(new Buffer<BUF_SIZE>));
return (*stream_.rbegin())->read(fd);
}
};
在评论中,您提到您希望避免创建大的字符缓冲区。使用read
系统调用时,执行少量大读取通常比执行许多小读取更有效。因此,大多数实现将选择大输入缓冲区来获得这种效率。你可以实现类似的东西:
std::vector<char> input;
char in;
int r;
while ((r = read(fd, &in, 1)) == 1) input.push_back(in);
但这将涉及系统调用和为每个输入字节复制至少一个字节。相比之下,我提出的代码避免了额外的数据副本。
我真的不希望我发布的代码是您会采用的解决方案。我只是想为您提供一个说明,说明如何创建一个相当节省空间和时间的自扩展对象。根据您的目的,您可能想要扩展它,或编写自己的。在我的脑海中,一些改进可能是:
- 改为使用
std::list
,以避免矢量调整大小
- 允许 API 一个参数来指定读取多少字节
- 用于始终允许一次读取
readv
至少BUF_SIZE
字节(或多于字节)BUF_SIZE