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

Must I open a file in [ios::binary] mode to get its size?

本文关键字:文件 ios 模式 binary      更新时间:2023-10-16
#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包含许多rn序列,C++标准是否保证GetFileSizeAGetFileSizeB相同?

该标准绝不保证两者相等(C 或 C++ 标准也不声明文件是否包含 rnnr 作为行尾,由操作系统和/或应用程序定义。标准 C 库,以及扩展的 C++ 库,保证如果你以文本模式读取文件,它会将任何实际的行尾转换为内部n形式)。它也不能保证它并不总是相同的值。

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

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

事实上,代码

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

也不能保证按预期工作。基于文件的流的tellg()操作归结为几个中间函数(std::basic_istream::tellg -> std::basic_streambuf::pubseekoff -> std::basic_filebuf::seekoff),并使用"好像"公式来std::fseek()。后者不需要支持相对于结束位置的二进制流中的搜索:

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

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

如果流以二进制模式打开,则新位置正好 如果原点为 SEEK_SET,如果原点为SEEK_CUR,则从当前文件位置开始, 如果原点为 SEEK_END,则从文件末尾开始。二进制流 不需要支持SEEK_END,特别是如果 输出空字节