




最推荐用 std::filesystem::file_size,但需 C++17 支持且路径必须为真实常规文件;否则可用 seekg + tellg(须二进制模式并检查状态);seekp 不可用于获取文件大小。
std::filesystem::file_size 最直接,但要注意 C++17 及路径有效性这是目前最推荐的方式,无需手动打开文件、不依赖流状态,一行就能拿到字节数:std::filesystem::file_size("path.txt")。但它要求编译器支持 C++17(GCC 8+、Clang 7+、MSVC 2017 15.7+),且传入的路径必须是真实存在的常规文件——如果路径不存在、是目录、或权限不足,会抛出 std::filesystem::filesystem_error 异常。
常见错误现象:程序崩溃或未捕获异常导致终止;误把符号链接当普通文件(默认不解析);在 Windows 上传入带中文路径但没用 UTF-8 编码的 std::filesystem::path 对象。
-std=c++17(GCC/Clang)或设置项目标准为 C++17(MSVC)std::filesystem::exists(p) 和 std::filesystem::is_regular_file(p)
std::filesystem::file_size(p, ec) 配合 std::error_code,或显式调用 std::filesystem::canonical(p)
seekg + tellg 获取大小,适用于老标准或需要复用已打开流的场景当不能用 std::filesystem(比如要兼容 C++11),或你已经以 std::ifstream 打开了文件并想顺便查大小,可以用定位 + 查询方式。核心是:将读位置移到末尾,再读当前位置值。
关键点不是 seekp(那是输出流用的),而是输入流的 seekg。常见错误是忘记清空流状态位(如 failbit)、没指定 std::ios::end 模式、或用 tellg() 返回 -1 后未判断就直接当大小用。
std::ios::binary 模式打开,否则文本模式下 seekg 行为不可靠(尤其 Windows 换行符)seekg(0, std::ios::end) 后,立即检查 !ifs.fail();失败则大小未知tellg() 返回 std::streampos,转 std::uintmax_t 前先确认非 -1(static_cast<:uintmax_t>(pos))ifs.seekg(0, std::ios::beg)
seekp 在输出流里不能用来“查大小”,但能控制写入位置seekp 是 std::ofstream 或 std::fstream(输出方向)的成员函数,只影响下次写入的起始偏移,和当前文件长度无关。有人误以为 ofs.seekp(0, std::ios::end); ofs.tellp() 能得到大小,这在文件刚创建且没写入时可能碰巧对,但一旦文件有内容、或被其他进程修改、或流缓冲未刷新,结果就不可信。
真正可靠的大小始终以磁盘上实际字节数为准,seekp/tellp 只反映流内部写指针位置,不等于文件系统元数据。
tellp() 替代 file_size() 或 tellg()
seekp 是合适的,但得确保文件已存在且足够大,或先用 seekp 写零填充ofs.flush(),否则 tellp() 可能滞后于实际磁盘写入std::filesystem 路径编码容易踩坑在 MSVC 下,std::filesystem::path 默认用窄字符串(char),但 Windows API 实际期望 UTF-16。如果路径含中文、日文等,直接传 "测试.txt" 字面量,在非 UTF-8 系统 locale 下大概率失败。
s
td::filesystem::u8path(u8"测试.txt")(C++20)或手动构造 std::filesystem::path 从宽字符串(std::wstring)std::filesystem::absolute(p).string() 看是否乱码,是快速定位编码问题的手段file_size 最简洁,但异常和编码是高频失手点;seekg/tellg 更底层,适合嵌入已有 IO 流逻辑,但二进制模式和状态检查缺一不可;至于 seekp,它真不是用来查大小的。