将整个 ASCII 文件读入 C++ std::string

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2602013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 00:02:54  来源:igfitidea点击:

Read whole ASCII file into C++ std::string

c++stringcachingfile-iostandard-library

提问by Escualo

I need to read a whole file into memory and place it in a C++ std::string.

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

If I were to read it into a char[], the answer would be very simple:

如果我将其读入 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 ...

Now, I want to do the exact same thing, but using a std::stringinstead of a char[]. I want to avoid loops, i.e. I don'twant to:

现在,我想做完全相同的事情,但使用 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()

Any ideas?

有任何想法吗?

采纳答案by Tyler McHenry

Update:Turns out that this method, while following STL idioms well, is actually surprisingly inefficient! Don't do this with large files. (See: http://insanecoding.blogspot.com/2011/11/how-to-read-in-file-in-c.html)

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

You can make a streambuf iterator out of the file and initialize the string with it:

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

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

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

Not sure where you're getting the t.open("file.txt", "r")syntax from. As far as I know that's not a method that std::ifstreamhas. It looks like you've confused it with C's fopen.

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

Edit:Also note the extra parentheses around the first argument to the string constructor. These are essential. They prevent the problem known as the "most vexing parse", which in this case won't actually give you a compile error like it usually does, but will give you interesting (read: wrong) results.

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

Following KeithB's point in the comments, here's a way to do it that allocates all the memory up front (rather than relying on the string class's automatic reallocation):

遵循 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>());

回答by Jerry Coffin

There are a couple of possibilities. One I like uses a stringstream as a go-between:

有几种可能性。我喜欢使用 stringstream 作为中间人:

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

Now the contents of "file.txt" are available in a string as buffer.str().

现在“file.txt”的内容在一个字符串中可用buffer.str()

Another possibility (though I certainly don't like it as well) is much more like your original:

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

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

Officially, this isn't required to work under the C++98 or 03 standard (string isn't required to store data contiguously) but in fact it works with all known implementations, and C++11 and later do require contiguous storage, so it's guaranteed to work with them.

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

As to why I don't like the latter as well: first, because it's longer and harder to read. Second, because it requires that you initialize the contents of the string with data you don't care about, then immediately write over that data (yes, the time to initialize is usually trivial compared to the reading, so it probably doesn't matter, but to me it still feels kind of wrong). Third, in a text file, position X in the file doesn't necessarily mean you'll have read X characters to reach that point -- it's not required to take into account things like line-end translations. On real systems that do such translations (e.g., Windows) the translated form is shorter than what's in the file (i.e., "\r\n" in the file becomes "\n" in the translated string) so all you've done is reserved a little extra space you never use. Again, doesn't really cause a major problem but feels a little wrong anyway.

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

回答by mili

I think best way is to use string stream. simple and quick !!!

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

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

回答by Ankit Acharya

You may not find this in any book or site but I found out that it works pretty well:

您可能在任何书籍或网站上都找不到它,但我发现它运行良好:

ifstream ifs ("filename.txt");
string s;
getline (ifs, s, (char) ifs.eof());

回答by madx

Try one of these two methods:

尝试以下两种方法之一:

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
}

回答by yash101

I figured out another way that works with most istreams, including std::cin!

我想出了另一种适用于大多数 istreams 的方法,包括 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();
    }
}

回答by chunkyguy

I could do it like this:

我可以这样做:

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

If this is something to be frowned upon, please let me know why

如果这是令人不悦的事情,请告诉我原因

回答by Artem Vorotnikov

If you happen to use glibmmyou can try Glib::file_get_contents.

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

回答by KeithB

I don't think you can do this without an explicit or implicit loop, without reading into a char array (or some other container) first and ten constructing the string. If you don't need the other capabilities of a string, it could be done with vector<char>the same way you are currently using a char *.

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