C++二进制文件和迭代器:使用ifstreambuf_titerator实现1:1

C++ binary files and iterators: getting away with a 1:1 using ifstreambuf_iterator?

本文关键字:实现 ifstreambuf titerator 使用 二进制文件 迭代器 C++      更新时间:2023-10-16

这个答案指出了一个事实,C++不太适合对二进制文件进行迭代,但这正是我现在需要的,简而言之,我需要以"二进制"的方式对文件进行操作,是的,所有文件都是二进制的,甚至是.txt文件,但我正在写一些对图像文件进行操作的东西,所以我需要读取结构良好的文件,如果数据以特定方式排列。

我想读取std::vector<T>等数据结构中的整个文件,这样我几乎可以立即关闭文件并处理内存中的内容,而不再关心磁盘I/O。

现在,根据标准库对文件执行完整迭代的最佳方式是

std::ifstream ifs(filename, std::ios::binary);
  for (std::istreambuf_iterator<char, std::char_traits<char> > it(ifs.rdbuf());
       it != std::istreambuf_iterator<char, std::char_traits<char> >(); it++) {
    // do something with *it;
  }
ifs.close();

或者使用std::copy,但即使使用std::copy,您也总是使用istreambuf迭代器(因此,如果我正确理解C++文档,您基本上在每次调用前一个代码时读取1个字节)。

所以问题是:如何编写自定义迭代器?我应该从哪里继承?

我认为这在将文件写入磁盘时也很重要,我认为我可以使用相同的迭代器类进行写入,如果我错了,请随时更正。

使用std::istreambuf_iterator<char>可以优化std::copy(),但几乎没有任何实现能做到这一点。仅仅从某个东西派生也不会真正奏效,因为迭代器不是这样工作的。

最有效的内置方法可能是简单地将文件转储到std::ostringstream中,然后从中获取std::string

std::ostringstream out;
out << file.rdbuf();
std::string content = out.str();

如果你想避免通过std::string,你可以写一个流缓冲区,直接将内容转储到内存区或std::vector<unsigned char>,也可以使用上面的输出操作。

原则上,std::istreambuf_iterator<char>可以有一个流缓冲区的后门,并绕过字符操作。如果没有后门,您将无法使用这些迭代器来加快任何速度。可以使用流缓冲区的sgetn()在流缓冲区之上创建迭代器来处理类似的缓冲区。在这种情况下,您几乎需要一个std::copy()版本来有效地处理段(即,每个缓冲区的填充)。除此之外,我只需使用流缓冲区将文件读取到缓冲区中,并对其进行迭代。

我的建议是不要使用自定义流、流缓冲区或流迭代器。

#include <fstream>
struct Data {
    short a;
    short b;
    int   c;
};
std::istream& operator >> (std::istream& stream, Data& data) {
    static_assert(sizeof(Data) == 2*sizeof(short) + sizeof(int), "Invalid Alignment");
    if(stream.read(reinterpret_cast<char*>(&data), sizeof(Data))) {
        // Consider endian
    }
    else {
        // Error
    }
    return stream;
}
int main(int argc, char* argv[])
{
    std::ifstream stream;
    Data data;
    while(stream >> data) {
        // Process
    }
    if(stream.fail()) {
        // Error (EOF is good)
    }
    return 0;
}

您可以大胆地让流缓冲区迭代器读取具有更大大小大于底层char_type:

  • 如果数据的格式无效怎么办
  • 如果数据不完整且处于EOF,该怎么办

流的状态不是由缓冲区或迭代器维护的。