如何优雅高效地将文件读入vector?
How to read a file into a vector elegantly and efficiently?
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
vector<char> f1()
{
ifstream fin{ "input.txt", ios::binary };
return
{
istreambuf_iterator<char>(fin),
istreambuf_iterator<char>()
};
}
vector<char> f2()
{
vector<char> coll;
ifstream fin{ "input.txt", ios::binary };
char buf[1024];
while (fin.read(buf, sizeof(buf)))
{
copy(begin(buf), end(buf),
back_inserter(coll));
}
copy(begin(buf), begin(buf) + fin.gcount(),
back_inserter(coll));
return coll;
}
int main()
{
f1();
f2();
}
很明显,f1()
比f2()
更简洁;所以我更喜欢 f1()
而不是 f2()
。但是,我担心 f1()
的效率不如 f2()
。
那么,我的问题是:
主流 C++ 编译器会优化 f1()
使其与 f2()
一样快吗?
更新:
我用了一个130M的文件在release模式下测试(Visual Studio 2015 with Clang 3.8):
f1()
需要 1614
毫秒,而 f2()
需要 616
毫秒。
f2()
比 f1()
.
快
多么可悲的结果!
我已经使用 with mingw482
检查了我这边的代码。
出于好奇,我添加了一个附加函数 f3
,实现如下:
inline vector<char> f3()
{
ifstream fin{ filepath, ios::binary };
fin.seekg (0, fin.end);
size_t len = fin.tellg();
fin.seekg (0, fin.beg);
vector<char> coll(len);
fin.read(coll.data(), len);
return coll;
}
我已经使用 ~90M
长的文件进行了测试。对于我的平台,结果与您的有所不同。
- f1() ~850 毫秒
- f2() ~600 毫秒
- f3() ~70 毫秒
结果计算为 10 次连续文件读取的平均值。
f3
函数花费的时间最少,因为在 vector<char> coll(len);
时它已分配了所有必需的内存并且不需要进行进一步的重新分配。至于 back_inserter 它要求类型具有 push_back
成员函数。当超过 capacity
时,哪个 for vector 会重新分配。如文档中所述:
push_back
This effectively increases the container size by one, which causes an
automatic reallocation of the allocated storage space if -and only if-
the new vector size surpasses the current vector capacity.
在 f1
和 f2
实现中,后者稍快一些,尽管两者都使用 back_inserter
。 f2
可能更快,因为它以块的形式读取文件,这允许进行一些缓冲。
如果小于几 GB,您可以一次全部读取:
#include "sys/stat.h"
....
char* buf;
FILE* fin;
filename="myfile.cgt";
#ifdef WIN32
struct stat st;
if (stat(filename, &st) == -1) return 0;
#else
struct _stat st;
if (_stat(filename, &st) == -1) return 0;
#endif
fin = fopen(filename, "rb");
if (!fin) return 0;
buf = (char*)malloc(st.st_size);
if (!buf) {fclose(fin); return 0;}
fread(buf, st.st_size, 1, fin);
fclose(fin);
不用说你应该在 C++ 中使用 "new" 而不是 malloc()
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
vector<char> f1()
{
ifstream fin{ "input.txt", ios::binary };
return
{
istreambuf_iterator<char>(fin),
istreambuf_iterator<char>()
};
}
vector<char> f2()
{
vector<char> coll;
ifstream fin{ "input.txt", ios::binary };
char buf[1024];
while (fin.read(buf, sizeof(buf)))
{
copy(begin(buf), end(buf),
back_inserter(coll));
}
copy(begin(buf), begin(buf) + fin.gcount(),
back_inserter(coll));
return coll;
}
int main()
{
f1();
f2();
}
很明显,f1()
比f2()
更简洁;所以我更喜欢 f1()
而不是 f2()
。但是,我担心 f1()
的效率不如 f2()
。
那么,我的问题是:
主流 C++ 编译器会优化 f1()
使其与 f2()
一样快吗?
更新:
我用了一个130M的文件在release模式下测试(Visual Studio 2015 with Clang 3.8):
f1()
需要 1614
毫秒,而 f2()
需要 616
毫秒。
f2()
比 f1()
.
多么可悲的结果!
我已经使用 with mingw482
检查了我这边的代码。
出于好奇,我添加了一个附加函数 f3
,实现如下:
inline vector<char> f3()
{
ifstream fin{ filepath, ios::binary };
fin.seekg (0, fin.end);
size_t len = fin.tellg();
fin.seekg (0, fin.beg);
vector<char> coll(len);
fin.read(coll.data(), len);
return coll;
}
我已经使用 ~90M
长的文件进行了测试。对于我的平台,结果与您的有所不同。
- f1() ~850 毫秒
- f2() ~600 毫秒
- f3() ~70 毫秒
结果计算为 10 次连续文件读取的平均值。
f3
函数花费的时间最少,因为在 vector<char> coll(len);
时它已分配了所有必需的内存并且不需要进行进一步的重新分配。至于 back_inserter 它要求类型具有 push_back
成员函数。当超过 capacity
时,哪个 for vector 会重新分配。如文档中所述:
push_back
This effectively increases the container size by one, which causes an automatic reallocation of the allocated storage space if -and only if- the new vector size surpasses the current vector capacity.
在 f1
和 f2
实现中,后者稍快一些,尽管两者都使用 back_inserter
。 f2
可能更快,因为它以块的形式读取文件,这允许进行一些缓冲。
如果小于几 GB,您可以一次全部读取:
#include "sys/stat.h"
....
char* buf;
FILE* fin;
filename="myfile.cgt";
#ifdef WIN32
struct stat st;
if (stat(filename, &st) == -1) return 0;
#else
struct _stat st;
if (_stat(filename, &st) == -1) return 0;
#endif
fin = fopen(filename, "rb");
if (!fin) return 0;
buf = (char*)malloc(st.st_size);
if (!buf) {fclose(fin); return 0;}
fread(buf, st.st_size, 1, fin);
fclose(fin);
不用说你应该在 C++ 中使用 "new" 而不是 malloc()