最近我被要求编写一个函数,将二进制文件读入std::vector<BYTE>
,其中BYTE
是unsigned char
,很快我就得到了这样的结果:
#include <fstream>
#include <vector>
typedef unsigned char BYTE;
std::vector<BYTE> readFile(const char* filename)
{
// open the file:
std::streampos fileSize;
std::ifstream file(filename, std::ios::binary);
// get its size:
file.seekg(0, std::ios::end);
fileSize = file.tellg();
file.seekg(0, std::ios::beg);
// read the data:
std::vector<BYTE> fileData(fileSize);
file.read((char*) &fileData[0], fileSize);
return fileData;
}
这似乎是不必要的复杂,并且在调用file.read
时被迫使用的char*
的显式强制转换并没有让我感觉好一点。
另一个选项是使用std::istreambuf_iterator
:
std::vector<BYTE> readFile(const char* filename)
{
// open the file:
std::ifstream file(filename, std::ios::binary);
// read the data:
return std::vector<BYTE>((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
}
这是非常简单和简短的,但我仍然必须使用std::istreambuf_iterator<char>
,即使当我阅读std::vector<unsigned char>
时。
最后一个看起来非常简单的选项是使用std::basic_ifstream<BYTE>
,它明确地表达了 “我想要一个输入文件流,我想用它来读取BYTE
s”:
std::vector<BYTE> readFile(const char* filename)
{
// open the file:
std::basic_ifstream<BYTE> file(filename, std::ios::binary);
// read the data:
return std::vector<BYTE>((std::istreambuf_iterator<BYTE>(file)),
std::istreambuf_iterator<BYTE>());
}
但我不确定basic_ifstream
在这种情况下是否是合适的选择。
- 将二进制文件读入
vector
的最佳方法是什么?* 我还想知道 *“幕后”发生了什么 * 以及我可能遇到的问题是什么(除了流无法正确打开,这可能通过简单的is_open
检查来避免)。
有没有什么好的理由说明为什么这里更喜欢使用std::istreambuf_iterator
?
(the我能看到的唯一优点是简单)
5条答案
按热度按时间pgccezyw1#
在测试性能时,我将包括以下测试用例:
我的想法是方法1的构造函数接触
vector
中的元素,然后read
再次接触每个元素。方法2和方法3看起来最有希望,但可能会遇到一个或多个
resize
。因此,在阅读或插入之前要使用reserve
。我还将使用
std::copy
进行测试:最后,我认为最好的解决方案是避免
istream_iterator
中的operator >>
(以及operator >>
试图解释二进制数据的所有开销和好处),但是我不知道使用什么来允许您直接将数据复制到向量中。最后,我用二进制数据进行的测试显示
ios::binary
没有被接受,因此noskipws
从<iomanip>
变为noskipws
。okxuctiv2#
kx7yvsdv3#
因为你要把整个文件加载到内存中,所以最好的方法是把文件Map到内存中,这是因为内核无论如何都会把文件加载到内核页面缓存中,通过Map文件,你只是把该高速缓存中的页面暴露给你的进程,也称为零拷贝。
当您使用
std::vector<>
时,它会将数据从内核页面缓存复制到std::vector<>
中,而当您只想读取文件时,这是不必要的。另外,当传递两个输入迭代器到
std::vector<>
时,它会在阅读时增加缓冲区,因为它不知道文件大小。当首先将std::vector<>
调整到文件大小时,它不必要地将其内容清零,因为它无论如何都会被文件数据覆盖。这两种方法在空间和时间方面都是次优的。yhived7q4#
我本来会认为第一种方法,使用大小和使用
stream::read()
将是最有效的,强制转换到char *
的“成本”很可能是零--这种类型的强制转换只需告诉编译器“嘿,我知道你认为这是一个不同的类型,但我真的想要这个类型在这里...",并且不添加任何额外的instructionons--如果你希望确认这一点,试着将文件读入一个字符数组,然后与实际的汇编代码进行比较,除了需要做一些额外的工作来确定向量中缓冲区的地址之外,应该没有任何区别。和往常一样,在你的情况下,唯一能确定什么是最有效的方法就是衡量它。“在网上问”不是证据。
50few1ms5#
下面的类使用二进制文件加载和保存来扩展vector。我已经多次返回过这个问题,所以这是我下一次返回的代码--以及所有其他将寻找二进制文件保存方法的人。
用法示例