谁还没个明天
2010-04-08 17:19
采纳率: 50%
浏览 340

将整个 ASCII 文件读入 c + + std: : string [ duplicate ]

This question already has an answer here:

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

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

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::string instead of a char[]. I want to avoid loops, i.e. I don't want to:

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?

</div>

转载于:https://stackoverflow.com/questions/2602013/read-whole-ascii-file-into-c-stdstring

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

9条回答 默认 最新

  • 7*4 2010-04-08 17:23
    已采纳

    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)

    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::ifstream has. It looks like you've confused it with 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):

    #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-08 17:30

    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 *.

    打赏 评论
  • 笑故挽风 2010-04-08 17:53

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

    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().

    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.

    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.

    打赏 评论
  • 妄徒之命 2012-10-22 12:55

    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

    打赏 评论
  • 斗士狗 2013-11-12 06:08

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

    ifstream inFile;
    inFile.open(inFileName);//open the input file
    
    stringstream strStream;
    strStream << inFile.rdbuf();//read the file
    string str = strStream.str();//str holds the content of the file
    
    cout << str << endl;//you can do anything with the string!!!
    
    打赏 评论
  • 喵-见缝插针 2014-08-20 05:23

    I figured out another way that works with most istreams, including 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();
    }
    }
    
    打赏 评论
  • 游.程 2015-02-05 12:50

    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
    }
    
    打赏 评论
  • 撒拉嘿哟木头 2015-11-10 16:48

    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());
    
    打赏 评论
  • 北城已荒凉 2016-08-07 14:55

    If you happen to use glibmm you can try 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;
    }
    
    打赏 评论

相关推荐 更多相似问题