How do I read an entire file into a std::string in C++?

后端 未结 15 1940
余生分开走
余生分开走 2020-11-21 23:51

How do I read a file into a std::string, i.e., read the whole file at once?

Text or binary mode should be specified by the caller. The solution should b

相关标签:
15条回答
  • 2020-11-22 00:18

    The shortest variant: Live On Coliru

    std::string str(std::istreambuf_iterator<char>{ifs}, {});
    

    It requires the header <iterator>.

    There were some reports that this method is slower than preallocating the string and using std::istream::read. However, on a modern compiler with optimisations enabled this no longer seems to be the case, though the relative performance of various methods seems to be highly compiler dependent.

    0 讨论(0)
  • 2020-11-22 00:19

    If you have C++17 (std::filesystem), there is also this way (which gets the file's size through std::filesystem::file_size instead of seekg and tellg):

    #include <filesystem>
    #include <fstream>
    #include <string>
    
    namespace fs = std::filesystem;
    
    std::string readFile(fs::path path)
    {
        // Open the stream to 'lock' the file.
        std::ifstream f(path, std::ios::in | std::ios::binary);
    
        // Obtain the size of the file.
        const auto sz = fs::file_size(path);
    
        // Create a buffer.
        std::string result(sz, '\0');
    
        // Read the whole file into the buffer.
        f.read(result.data(), sz);
    
        return result;
    }
    

    Note: you may need to use <experimental/filesystem> and std::experimental::filesystem if your standard library doesn't yet fully support C++17. You might also need to replace result.data() with &result[0] if it doesn't support non-const std::basic_string data.

    0 讨论(0)
  • 2020-11-22 00:20

    This solution adds error checking to the rdbuf()-based method.

    std::string file_to_string(const std::string& file_name)
    {
        std::ifstream file_stream{file_name};
    
        if (file_stream.fail())
        {
            // Error opening file.
        }
    
        std::ostringstream str_stream{};
        file_stream >> str_stream.rdbuf();  // NOT str_stream << file_stream.rdbuf()
    
        if (file_stream.fail() && !file_stream.eof())
        {
            // Error reading file.
        }
    
        return str_stream.str();
    }
    

    I'm adding this answer because adding error-checking to the original method is not as trivial as you'd expect. The original method uses stringstream's insertion operator (str_stream << file_stream.rdbuf()). The problem is that this sets the stringstream's failbit when no characters are inserted. That can be due to an error or it can be due to the file being empty. If you check for failures by inspecting the failbit, you'll encounter a false positive when you read an empty file. How do you disambiguate legitimate failure to insert any characters and "failure" to insert any characters because the file is empty?

    You might think to explicitly check for an empty file, but that's more code and associated error checking.

    Checking for the failure condition str_stream.fail() && !str_stream.eof() doesn't work, because the insertion operation doesn't set the eofbit (on the ostringstream nor the ifstream).

    So, the solution is to change the operation. Instead of using ostringstream's insertion operator (<<), use ifstream's extraction operator (>>), which does set the eofbit. Then check for the failiure condition file_stream.fail() && !file_stream.eof().

    Importantly, when file_stream >> str_stream.rdbuf() encounters a legitimate failure, it shouldn't ever set eofbit (according to my understanding of the specification). That means the above check is sufficient to detect legitimate failures.

    0 讨论(0)
提交回复
热议问题