I've tried various idiomatic C++ solutions for reading a file into a std::string on Windows and it has been giving me tons of headaches since the std::string length was consistently wrong (e.g. much smaller than the original file). The same codes all worked perfectly on Linux though.
The following functions all misbehave on Windows:
#include <boost/filesystem.hpp>
#include <iostream>
#include <sstream>
using namespace boost::filesystem;
using namespace boost::iostreams;
std::string read_string_from_file_using_streams(const path &file_path) {
return read_string_from_file_using_streams(file_path.parent_path(), file_path.filename().string());
}
std::string read_string_from_file_using_streams(const path &parent_directory, const std::string &file_name) {
const auto original_file_path =
parent_directory.string() + (char) path::preferred_separator + file_name;
const std::ifstream input_stream(original_file_path);
if (input_stream.fail()) {
throw std::runtime_error("File is not readable");
}
std::stringstream buffer;
buffer << input_stream.rdbuf(); // Does not read the whole file on Windows!
return buffer.str();
}
std::string read_string_from_file_with_string_pre_allocation(const std::string& path) {
std::ifstream t(path);
std::string str;
t.seekg(0, std::ios::end);
str.reserve(t.tellg()); // Reserves the correct length
t.seekg(0, std::ios::beg);
str.assign(std::istreambuf_iterator<char>(t), // Does not read the whole file on Windows!
std::istreambuf_iterator<char>());
return str;
}
std::string read_string_from_file_using_if_stream(const std::string& path) {
std::ifstream file(path);
return std::string(std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()); // Does not read the whole file on Windows!
}
Finally, the following C standard code example works properly:
std::string read_using_c_standard_library(const std::string& path) {
auto f = fopen(path.c_str(), "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET);
auto string = (char *) malloc(fsize + 1);
fread(string, 1, fsize, f); // This reads the whole file on Windows, finally!
fclose(f);
string[fsize] = 0;
std::string s(string, fsize);
free(string);
return s;
}
I don't understand why this is happening. What's wrong with the C++ code approaches? My example file is 516 KB and the buggy functions only read e.g. 912 bytes.