如何优雅高效地将文件读入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.

f1f2 实现中,后者稍快一些,尽管两者都使用 back_inserterf2 可能更快,因为它以块的形式读取文件,这允许进行一些缓冲。

如果小于几 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()