我必须在[ios :: binary]模式下打开文件才能获得它的大小吗?

时间:2017-01-18 08:53:52

标签: c++ standards filestream portability

#include <fstream>
#include <string>
#include <cassert>

long long GetFileSizeA(const std::string& file_path)
{
    return std::ifstream
    {
        file_path, std::ios::ate    
    }.tellg();
}

long long GetFileSizeB(const std::string& file_path)
{
    return std::ifstream
    {
        file_path, std::ios::ate | std::ios::binary 
    }.tellg();
}

int main()
{
    auto a = GetFileSizeA("~/test.log");
    auto b = GetFileSizeB("~/test.log");

    assert(a == b); // always true?
}

如果文件~/test.log包含许多\r\n个序列,那么C ++标准保证GetFileSizeA是否与GetFileSizeB相同?

2 个答案:

答案 0 :(得分:1)

标准不能保证两者相等(C或C ++标准也没有说明文件是否包含\r\n\n\r作为行尾,由操作系统和/或应用程序定义。标准C库,以及扩展的C ++库,保证如果您以文本模式读取文件,它将把任何实际的行结束转换为内部\n形式)。它也不能保证它始终不是相同的值。

更重要的是,您可能会发现,如果您阅读文件的某些部分并询问“我在哪里”,那么如果您将其读作二进制文件或ascii文件,则答案会有所不同。如果您计划将文件映射到内存并将其作为大字符串处理,而不转换换行符,则需要将其作为二进制文件。

答案 1 :(得分:1)

C ++标准没有这样的保证。

实际上,代码

std::ifstream{file_path, std::ios::ate | std::ios::binary}.tellg();

也不保证按预期工作。对基于文件的流的tellg()操作归结为几个中间函数(std::basic_istream::tellg - &gt; std::basic_streambuf::pubseekoff - &gt; std::basic_filebuf::seekoff)并使用'好像'制定为std::fseek()。后者isn't required to support seeking in binary streams relative to the end position

  

int fseek( std::FILE* stream, long offset, int origin );

     

设置文件流流的文件位置指示符。

     

如果流以二进制模式打开,则新位置完全正确   如果原点是从文件开头测量的偏移字节   SEEK_SET,如果来源为SEEK_CUR,则从当前文件位置开始,   如果来源是SEEK_END,则从文件末尾开始。 二进制流   不需要支持SEEK_END,特别是如果有额外的话   输出空字节