在编程中,有一种称为生成器的东西;在C++中,我们倾向于将它们视为输入迭代器,但关注点仍然相同:就像管道一样,它是基于拉动驱动的生产。
因此,您可以围绕生产者(最好具有输入迭代器的接口)和消费者的想法重构程序,并且消费者将逐行请求输入,而生产者将懒洋洋地提供。
对于必要接口的良好指南,我建议使用受人尊敬的SGI STL网站:这里是
InputIterator概念的链接。
对于一个更简单的例子,假设我们不必处理解压缩,只需按行读取文件:
class LineIterator: public std::iterator<std::input_iterator_tag,
std::string const>
{
public:
LineIterator(): stream(nullptr) {}
explicit LineIterator(std::istream& is): stream(&is) { this->advance(); }
friend bool operator==(LineIterator const& left, LineIterator const& right) {
return left.stream == right.stream
and left.buffer == right.buffer
and left.currentLine == right.currentLine;
}
friend bool operator!=(LineIterator const& left, LineIterator const& right) {
return not (left == right);
}
pointer operator->() const { return ¤tLine; }
reference operator*() const { return currentLine; }
LineIterator& operator++() {
this->advance();
return *this;
}
LineIterator operator++(int) {
LineIterator tmp(*this);
++*this;
return tmp;
}
private:
void advance() {
static LineIterator const SingularValue;
assert(*this != SingularValue and "Cannot advance singular iterator");
currentLine.clear();
swap(buffer, currentLine);
size_t const nl = currentLine.find('\n');
if (nl != std::string::npos) {
if (nl == currentLine.size()) { return; }
buffer.assign(currentLine.begin() + nl + 1, currentLine.end());
currentLine.erase(currentLine.begin() + nl + 1, currentLine.end());
return;
}
if (not stream) { return; }
static size_t const ReadBufferSize = 256;
char input[ReadBufferSize];
while (stream->read(input, ReadBufferSize)) {
if (this->splitBuffer(input, ReadBufferSize)) { break; }
}
if (*stream) { return; }
this->splitBuffer(input, stream->gcount());
stream = SingularValue.stream;
}
bool splitBuffer(char const* input, size_t const size) {
char const* const newLine = std::find(input, input + size, '\n');
if (newLine == input + size) {
currentLine.append(input, size);
return false;
}
currentLine.append(input, newLine + 1);
buffer.assign(newLine + 1, input + size);
return true;
}
std::istream* stream;
std::string buffer;
std::string currentLine;
};
这可能有点啰嗦(而且可能存在漏洞...),但它具有我们需要与STL算法组合的接口,例如:
std::ifstream file("someFile.txt");
std::copy(LineIterator(file), LineIterator(), std::ostream_iterator(std::cout));
这将会逐行在终端上输出文件 (点此查看示例)。
现在,您需要用块读取和解压缩来替换获取部分 (stream.read
) :)
pipe
系统调用来创建管道。一个线程解压文件并将其写入管道;另一个线程从管道中读取数据并执行相应操作。至于通过这种方式是否会得到任何好处,这是一个未知的问题。 - Duck