代码之家  ›  专栏  ›  技术社区  ›  BullyWiiPlaza

为什么在Windows上读取std::string文件的长度错误?

  •  1
  • BullyWiiPlaza  · 技术社区  · 5 年前

    我试过各种习语 C++ std::string Windows 自从 长度始终是错误的(例如,比原始文件小得多)。同样的代码都能很好地工作 Linux 不过。

    以下函数都在 :

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

    最后,如下 C

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

    C++ 代码方法?我的示例文件是 516 KB 912 bytes .

    1 回复  |  直到 5 年前
        1
  •  3
  •   john    5 年前

    你能看出区别吗?

    const std::ifstream input_stream(original_file_path);
    
    auto f = fopen(path.c_str(), "rb");
    

    这就是说,代码仍然应该读取整个文件,但它将更改行尾,因此结果字符串的大小可能不是您期望的那样。

        2
  •  1
  •   Andreas Wenzel    5 年前

    在Windows上,文本文件的行尾通常是 \r\n ,在Linux上,它们只是 \n .

    以文本模式打开文件会导致 要转换为的行尾 ,所以他们是 在两个平台上。

    但是,这应该只针对文本文件,而不是二进制文件,因为否则 \r\n 字节序列将转换为 ,从而损坏数据并使文件更短。

    另外,在Windows的文本模式下,一个字节的值 0x1A 被解释为文件结束(EOF)标记,即使实际文件长度较长。不过,在二进制模式下,具有此值的字节不会被解释为具有任何特殊含义。

    std::ifstream file(path);

    auto f = fopen(path.c_str(), "rb");

    将以二进制模式打开文件。

    这可能就是为什么你得到不同的文件长度。