将文件加载到向量<char>中

Man*_*rse 19 c++ iostream

我想将文本文件的内容加载到vector<char>(或任何char输入迭代器中,如果可能的话).目前我的代码如下所示:

std::vector<char> vec;
std::ifstream file("test.txt");
assert(file.is_open());
while (!(file.eof() || file.fail())) {
    char buffer[100];
    file.read(buffer, 100);
    vec.insert(vec.end(), buffer, buffer + file.gcount());
}
Run Code Online (Sandbox Code Playgroud)

我不喜欢手动使用缓冲区(为什么100个字符?为什么不是200个,或者25个或者其他什么?),或者这个用了大量的行.代码看起来非常丑陋而且非C++.有更直接的方法吗?

ham*_*ene 17

如果你想避免通过char读取char:

if (!file.eof() && !file.fail())
{
    file.seekg(0, std::ios_base::end);
    std::streampos fileSize = file.tellg();
    vec.resize(fileSize);

    file.seekg(0, std::ios_base::beg);
    file.read(&vec[0], fileSize);
}
Run Code Online (Sandbox Code Playgroud)

  • 实际上,经过谷歌搜索,我发现[这篇文章](http://cpp.indi.frih.net/blog/2014/09/how-to-read-an-entire-file-into-memory-in-cpp/ ).答案在Bad idea#2部分.基本上,它会导致未定义的行为. (4认同)
  • 整洁的解决方案,但这样安全吗? (3认同)

Kil*_*nDS 10

我认为它是这样的,但没有环境来测试它:

std::copy(std::istream_iterator<char>(file), std::istream_iterator<char>(), std::back_inserter(vec));
Run Code Online (Sandbox Code Playgroud)

可能你必须使用io操纵器来处理换行/空白等事情.

编辑:如评论中所述,可能会受到影响.

  • 坚持,我说谎,你是对的,需要一个io操纵器来处理空白.所需的迭代器对是`std :: istream_iterator <char>(文件>> std :: noskipws),std :: istream_iterator <char>()`. (3认同)
  • 还要注意,如果性能要求不是太紧,如果提问者真的只需要"任何字符输入迭代器",那么就不需要容器了.`std :: istream_iterator <char>(file),std :: istream_iterator <char>()`已经是请求的InputIterator对. (2认同)
  • 您的流将被缓冲,因此内核调用的开销应该很低.istream迭代器也可以在引擎盖下使用memcpy.这将有兴趣看看这和尤金的解决方案之间的性能差异,但我不认为差别会非常大. (2认同)

Fle*_*exo 6

另一种方法,用于rdbuf()首先读取整个文件std::stringstream

#include <fstream>
#include <sstream>
#include <vector>
#include <string>

// for check:
#include <algorithm>
#include <iterator>
#include <iostream>

int main() {
   std::ifstream file("test.cc");
   std::ostringstream ss;
   ss << file.rdbuf();
   const std::string& s = ss.str();
   std::vector<char> vec(s.begin(), s.end());

   // check:
   std::copy(vec.begin(), vec.end(), std::ostream_iterator<char>(std::cout));
}
Run Code Online (Sandbox Code Playgroud)


Man*_*rse 6

有很多好的回应。谢谢大家!我决定使用的代码是这样的:

std::vector<char> vec;
std::ifstream file;
file.exceptions(
    std::ifstream::badbit
  | std::ifstream::failbit
  | std::ifstream::eofbit);
//Need to use binary mode; otherwise CRLF line endings count as 2 for
//`length` calculation but only 1 for `file.read` (on some platforms),
//and we get undefined  behaviour when trying to read `length` characters.
file.open("test.txt", std::ifstream::in | std::ifstream::binary);
file.seekg(0, std::ios::end);
std::streampos length(file.tellg());
if (length) {
    file.seekg(0, std::ios::beg);
    vec.resize(static_cast<std::size_t>(length));
    file.read(&vec.front(), static_cast<std::size_t>(length));
}
Run Code Online (Sandbox Code Playgroud)

显然,这不适合非常大的文件或性能关键的代码,但对于一般用途来说已经足够了。


Adr*_*son 5

使用迭代器:

#include <iterator>

istream_iterator<char> data( file );
istream_iterator<char> end;
vec.insert( std::back_inserter(vec), data, end );
Run Code Online (Sandbox Code Playgroud)

  • 这不是一次读取一个角色**并且**跳过空白吗? (4认同)