C++二进制文件和迭代器:使用ifstreambuf_titerator实现1:1
C++ binary files and iterators: getting away with a 1:1 using ifstreambuf_iterator?
这个答案指出了一个事实,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,该怎么办
流的状态不是由缓冲区或迭代器维护的。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- std::random_device是如何实现的