将整个ASCII文件读入C++std::字符串

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

如果我把它读成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 ...

现在,我想做同样的事情,但是使用std::string而不是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()

有什么想法吗?

743171 次浏览

更新时间:事实证明,这种方法虽然很好地遵循了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的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>());

我认为如果没有显式或隐式循环,如果不首先读取char数组(或其他容器)并十构造字符串,你就无法做到这一点。如果你不需要字符串的其他功能,可以用vector<char>完成,就像你目前使用char *一样。

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

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”),因此您所做的只是保留了一点您从未使用过的额外空间。同样,这并没有真正引起大问题,但无论如何感觉有点错误。

我可以这样做:

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

如果这是令人不快的事情,请告诉我为什么

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

#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!!!
}

我想出了另一种方法,适用于大多数istreams,包括圣d::c!

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();
}
}

尝试以下两种方法之一:

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
}

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

#include <fstream>
// ...
std::string file_content;
std::getline(std::ifstream("filename.txt"), file_content, '\0');

如果您碰巧使用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;
}