670

我需要将整个文件读入内存并将其放在 C++std::string中。

如果我把它读成 a char[],答案会很简单:

std::ifstream t;
int length;
t.open("file.txt");      // open input file
t.seekg(0, std::ios::end);    // go to the end
length = t.tellg();           // report location (this is the length)
t.seekg(0, std::ios::beg);    // go back to the beginning
buffer = new char[length];    // allocate memory for a buffer of appropriate dimension
t.read(buffer, length);       // read the whole file into the buffer
t.close();                    // close file handle

// ... Do stuff with buffer here ...

现在,我想做完全相同的事情,但使用 astd::string而不是 a char[]。我想避免循环,即我不想

std::ifstream t;
t.open("file.txt");
std::string buffer;
std::string line;
while(t){
std::getline(t, line);
// ... Append line to buffer and go on
}
t.close()

有任何想法吗?

4

9 回答 9

973

有几种可能性。我喜欢使用字符串流作为中间人:

std::ifstream t("file.txt");
std::stringstream buffer;
buffer << t.rdbuf();

现在“file.txt”的内容以字符串形式提供buffer.str()

另一种可能性(尽管我当然也不喜欢它)更像你原来的:

std::ifstream t("file.txt");
t.seekg(0, std::ios::end);
size_t size = t.tellg();
std::string buffer(size, ' ');
t.seekg(0);
t.read(&buffer[0], size); 

正式地,这不需要在 C++98 或 03 标准下工作(字符串不需要连续存储数据),但实际上它适用于所有已知的实现,C++11 及更高版本确实需要连续存储,因此可以保证与他们合作。

至于为什么我也不喜欢后者:首先,因为它更长更难阅读。其次,因为它要求您使用您不关心的数据初始化字符串的内容,然后立即覆盖该数据(是的,与读取相比,初始化时间通常微不足道,所以这可能无关紧要,但对我来说仍然感觉有点不对)。第三,在文本文件中,文件中的位置 X 并不一定意味着您已经阅读了 X 个字符才能到达该位置——不需要考虑行尾翻译之类的事情。在进行此类翻译的实际系统(例如,Windows)上,翻译后的形式比文件中的短(即,文件中的“\r\n”在翻译后的字符串中变成“\n”)所以你所有的 ve done 保留了一点你从不使用的额外空间。同样,并没有真正引起重大问题,但无论如何感觉有点不对劲。

于 2010-04-08T17:53:26.820 回答
591

更新:事实证明,这种方法虽然很好地遵循了 STL 习语,但实际上效率低得惊人!不要对大文件执行此操作。(见:http: //insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html

您可以从文件中创建一个 streambuf 迭代器并用它初始化字符串:

#include <string>
#include <fstream>
#include <streambuf>

std::ifstream t("file.txt");
std::string str((std::istreambuf_iterator<char>(t)),
                 std::istreambuf_iterator<char>());

不确定您t.open("file.txt", "r")从哪里获得语法。据我所知,这不是一种方法std::ifstream。看起来你已经把它和 C's 混淆了fopen

编辑:还要注意字符串构造函数的第一个参数周围的额外括号。这些都是必不可少的。它们防止了被称为“最令人头疼的解析”的问题,在这种情况下,它实际上不会像通常那样给你一个编译错误,但会给你有趣的(阅读:错误)结果。

根据 KeithB 在评论中的观点,这是一种预先分配所有内存的方法(而不是依赖于字符串类的自动重新分配):

#include <string>
#include <fstream>
#include <streambuf>

std::ifstream t("file.txt");
std::string str;

t.seekg(0, std::ios::end);   
str.reserve(t.tellg());
t.seekg(0, std::ios::beg);

str.assign((std::istreambuf_iterator<char>(t)),
            std::istreambuf_iterator<char>());
于 2010-04-08T17:23:38.680 回答
84

我认为最好的方法是使用字符串流。简单快捷!!!

#include <fstream>
#include <iostream>
#include <sstream> //std::stringstream
int main() {
    std::ifstream inFile;
    inFile.open("inFileName"); //open the input file

    std::stringstream strStream;
    strStream << inFile.rdbuf(); //read the file
    std::string str = strStream.str(); //str holds the content of the file

    std::cout << str << "\n"; //you can do anything with the string!!!
}
于 2013-11-12T06:08:42.853 回答
26

你可能在任何书籍或网站上都找不到这个,但我发现它工作得很好:

#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');
于 2015-11-10T16:48:09.383 回答
7

尝试以下两种方法之一:

string get_file_string(){
    std::ifstream ifs("path_to_file");
    return string((std::istreambuf_iterator<char>(ifs)),
                  (std::istreambuf_iterator<char>()));
}

string get_file_string2(){
    ifstream inFile;
    inFile.open("path_to_file");//open the input file

    stringstream strStream;
    strStream << inFile.rdbuf();//read the file
    return strStream.str();//str holds the content of the file
}
于 2015-02-05T12:50:38.027 回答
2

我想出了另一种适用于大多数 istream 的方法,包括 std::cin!

std::string readFile()
{
    stringstream str;
    ifstream stream("Hello_World.txt");
    if(stream.is_open())
    {
        while(stream.peek() != EOF)
        {
            str << (char) stream.get();
        }
        stream.close();
        return str.str();
    }
}
于 2014-08-20T05:23:40.033 回答
1

如果你碰巧使用glibmm,你可以试试Glib::file_get_contents

#include <iostream>
#include <glibmm.h>

int main() {
    auto filename = "my-file.txt";
    try {
        std::string contents = Glib::file_get_contents(filename);
        std::cout << "File data:\n" << contents << std::endl;
    catch (const Glib::FileError& e) {
        std::cout << "Oops, an error occurred:\n" << e.what() << std::endl;
    }

    return 0;
}
于 2016-08-07T14:55:31.513 回答
0

我可以这样做:

void readfile(const std::string &filepath,std::string &buffer){
    std::ifstream fin(filepath.c_str());
    getline(fin, buffer, char(-1));
    fin.close();
}

如果这是不受欢迎的事情,请告诉我为什么

于 2012-10-22T12:55:00.643 回答
-5

我不认为你可以在没有显式或隐式循环的情况下做到这一点,而不先读入一个 char 数组(或其他容器),然后再读入十个构造字符串。如果您不需要字符串的其他功能,可以使用与vector<char>当前使用char *.

于 2010-04-08T17:30:26.380 回答