在C++中将文件内容读入字符串

110

“efficient” 是什么意思? - anon
7
高效 = 快速且不占用太多内存。 - sonofdelphi
7个回答

247

像这样:

#include <fstream>
#include <string>

int main(int argc, char** argv)
{

  std::ifstream ifs("myfile.txt");
  std::string content( (std::istreambuf_iterator<char>(ifs) ),
                       (std::istreambuf_iterator<char>()    ) );

  return 0;
}

这个语句

  std::string content( (std::istreambuf_iterator<char>(ifs) ),
                       (std::istreambuf_iterator<char>()    ) );

可以被拆分为

std::string content;
content.assign( (std::istreambuf_iterator<char>(ifs) ),
                (std::istreambuf_iterator<char>()    ) );

如果你只想覆盖现有的 std::string 变量的值,这很有用。


8
+1 非常符合 C++ 的风格。在 Linux 上使用 gcc 4.4,生成的系统调用非常高效,每次读取文件的大小为 8k。 - piotr
4
如果文件大小已知,可以在读取文件之前调用std::string::reserve 方法来分配空间。这将加快执行速度。重新分配字符串内存会浪费大量时间。 - Thomas Matthews
8
+1,但为什么迭代器必须用括号括起来?它们看起来无伤大雅,但不加括号编译会失败。 - Qix - MONICA WAS MISTREATED
9
Qix是“经典”的C++解析问题,被称为“最令人烦恼的解析”:http://en.wikipedia.org/wiki/Most_vexing_parse。 - fileoffset
我尝试了上述代码:content.assign((std::istreambuf_iterator<char>(ifs)), command。它可以很好地读取整个文件,但当我显示内容时,它显示在开头有无效字符。为什么?请帮忙。'code' string content; ifstream myfile("textFile.txt"); content.assign( (istreambuf_iterator<char>(myfile) ), (istreambuf_iterator<char>() ) ); cout<<content; - user1155921
显示剩余9条评论

46

最高效的方法,但不是 C++ 的方式:

   FILE* f = fopen(filename, "r");

   // Determine file size
   fseek(f, 0, SEEK_END);
   size_t size = ftell(f);

   char* where = new char[size];

   rewind(f);
   fread(where, sizeof(char), size, f);

   delete[] where;

#编辑 - 2

刚测试了使用std::filebuf的方法。看起来这可以被称为最好的C++方法,尽管它不完全是一个C++方法,而更像是一个包装器。无论如何,下面是一段代码块,它的速度几乎与普通的C语言相同。

   std::ifstream file(filename, std::ios::binary);
   std::streambuf* raw_buffer = file.rdbuf();

   char* block = new char[size];
   raw_buffer->sgetn(block, size);
   delete[] block;

我进行了一个快速的基准测试,结果如下。测试是在读取一个65536K二进制文件时进行的,使用适当的(std::ios:binaryrb)模式。

[==========] Running 3 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 4 tests from IO
[ RUN      ] IO.C_Kotti
[       OK ] IO.C_Kotti (78 ms)
[ RUN      ] IO.CPP_Nikko
[       OK ] IO.CPP_Nikko (106 ms)
[ RUN      ] IO.CPP_Beckmann
[       OK ] IO.CPP_Beckmann (1891 ms)
[ RUN      ] IO.CPP_Neil
[       OK ] IO.CPP_Neil (234 ms)
[----------] 4 tests from IO (2309 ms total)

[----------] Global test environment tear-down
[==========] 4 tests from 1 test case ran. (2309 ms total)
[  PASSED  ] 4 tests.

3
不错的基准测试,数字结果并不让我感到惊讶。对于纯ASCII文件的最大性能,使用老牌的C io是最好的选择。C++流根本无法匹敌。然而,它们更少出现错误。只要在分析时它们没有出现,我更喜欢使用它们。 - Maik Beckmann
2
哇,这真的很酷。我不知道为什么,但起初我并不信任你。看起来这是结合iostream功能和原始C文件读取速度的最佳方式。 - M. Williams
1
呵呵.. 普通C仍然更快 ;) - Felix
2
@Constantino,你计算文件长度的方法不太正确。虽然 fstat/rewind 的组合可以工作,但正确的方法是填充 stat 结构并提取 st_size 成员。最好还是保险一点。 - anon
4
你在这里如何找到尺寸?! - Urvashi Gupta
显示剩余5条评论

14

最有效的方法是创建一个正确大小的缓冲区,然后将文件读入缓冲区。

#include <fstream>
#include <vector>

int main()
{
    std::ifstream       file("Plop");
    if (file)
    {
        /*
         * Get the size of the file
         */
        file.seekg(0,std::ios::end);
        std::streampos          length = file.tellg();
        file.seekg(0,std::ios::beg);

        /*
         * Use a vector as the buffer.
         * It is exception safe and will be tidied up correctly.
         * This constructor creates a buffer of the correct length.
         * Because char is a POD data type it is not initialized.
         *
         * Then read the whole file into the buffer.
         */
        std::vector<char>       buffer(length);
        file.read(&buffer[0],length);
    }
}

基准测试?甚至是strace...(并不是我不相信这是最快的,我想知道它是否与基于迭代器的方法有任何区别) - Tronic
4
这种方法不能保证有效。tellg没有规定返回文件中的字节偏移量,它只是一个不透明的标记。请参见此答案以获取更详细的说明。 - M.M
在文本模式下,在执行文件转换的操作系统上,tellg 的结果很可能与可读取的字符数不匹配。 - M.M

8
文本文件中不应有\0
#include<iostream>
#include<fstream>

using namespace std;

int main(){
  fstream f(FILENAME, fstream::in );
  string s;
  getline( f, s, '\0');

  cout << s << endl;
  f.close();
}

7
问题没有提到文本文件。 - anon
3
这个例子只读取了一行,我不禁对其审核产生怀疑。 - piotr
5
这个例子会读取整个文本文件,已经测试过。 - Draco Ater
我认为大家都会认为它应该是一个文本文件,但实际上可能并非如此。至于代码:直接使用ifstream("文件名")可能更清晰一些。您不需要关闭文件,它会自动完成。而且它确实可以读取文本文件。 - Nikko
这个很棒。在我看来,这是整个主题中最相关的答案。它将整个东西存储在 C++ 字符串中,而不是字符数组。谢谢 Draco! - Martyn Chamberlin
显示剩余3条评论

4

这取决于很多因素,比如文件大小、文件类型(文本/二进制)等。之前我对下面的函数进行了基准测试,并与使用streambuf迭代器的版本进行了比较——速度大约快了两倍:

unsigned int FileRead( std::istream & is, std::vector <char> & buff ) {
    is.read( &buff[0], buff.size() );
    return is.gcount();
}

void FileRead( std::ifstream & ifs, string & s ) {
    const unsigned int BUFSIZE = 64 * 1024; // reasoable sized buffer
    std::vector <char> buffer( BUFSIZE );

    while( unsigned int n = FileRead( ifs, buffer ) ) {
        s.append( &buffer[0], n );
    }
}

3
也许不是最高效的方法,但可以在一行中读取数据:
#include<iostream>
#include<vector>
#include<iterator>

main(int argc,char *argv[]){
  // read standard input into vector:
  std::vector<char>v(std::istream_iterator<char>(std::cin),
                     std::istream_iterator<char>());
  std::cout << "read " << v.size() << "chars\n";
}

2
这是一种基于迭代器的方法。
ifstream file("file", ios::binary);
string fileStr;

istreambuf_iterator<char> inputIt(file), emptyInputIt
back_insert_iterator<string> stringInsert(fileStr);

copy(inputIt, emptyInputIt, stringInsert);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接