应使用 seekg(0, ios::end) 后调用 tellg() 获取文件大小,但必须以 ios::binary 模式打开;更可靠的方式是 stat() 或 C++17 的 std::filesystem::file_size()。

用 ifstream::tellg() 获取文件大小容易出错
直接调用 ifstream::tellg() 在未读取任何内容时返回 -1,不是文件大小;它返回的是当前读位置,不是文件总长度。必须先 seekg(0, ios::end) 移动到末尾,再 tellg() 才能得到字节数——但前提是文件以二进制模式打开,且流状态正常。
常见错误现象:tellg() 返回 -1、值异常小、或在 Windows 上对文本文件返回错误结果(换行符处理干扰)。
- 必须用
ios::binary模式打开文件,否则文本模式下\r\n可能被转换,tellg()不反映真实字节数 - 打开失败或文件为空时,
tellg()会返回 -1,需检查is_open()和good() - 操作后记得
seekg(0)回到开头,否则后续读取会从末尾开始
ifstream file("data.bin", ios::binary);
if (!file.is_open()) return -1;
file.seekg(0, ios::end);
streampos size = file.tellg(); // 正确:此时 size 是字节数
file.seekg(0); // 恢复读位置
stat() 是跨平台获取文件大小最稳的方式
stat() 是系统级调用,不依赖流状态,也不打开文件,直接查元数据,速度快、结果可靠。Windows 下用 _stat64() 或 GetFileAttributesEx(),Linux/macOS 直接用 stat()。C++17 起可用 std::filesystem::file_size() 封装,但底层仍是 stat 类接口。
注意:stat() 对符号链接默认返回链接本身大小(通常 0),如需目标文件大小,用 lstat()(Unix)或确保路径已解析(Windows)。
立即学习“C++免费学习笔记(深入)”;
- 头文件:Linux/macOS 用
<sys></sys>,Windows 用<sys></sys>(MSVC)或<io.h></io.h>(部分 MinGW) - 结构体字段:
st_size是off_t类型,32 位系统可能溢出大文件(>2GB),优先用stat64或_stat64 - 路径为相对路径时,以当前工作目录为基准,与
ifstream的行为一致
#ifdef _WIN32
struct _stat64 buf;
if (_stat64("data.bin", &buf) == 0) {
return buf.st_size;
}
#else
struct stat buf;
if (stat("data.bin", &buf) == 0) {
return buf.st_size;
}
#endif
C++17 std::filesystem::file_size() 看似简单,但有隐藏条件
它封装了平台差异,写法最简洁,但要求编译器开启 std::filesystem 支持(GCC 9+、Clang 9+、MSVC 2019+),且链接时需加 -lstdc++fs(GCC)或等效选项。更重要的是:它抛异常而非返回错误码,不捕获会终止程序。
典型错误:忘记 try/catch,或传入不存在路径、权限不足路径,导致 std::filesystem::filesystem_error 未处理。
- 路径参数是
std::filesystem::path,不能直接传 C 字符串(需构造或用u8path) - 若路径是符号链接,默认解析目标;要跳过解析,用
std::filesystem::symlink_status()+file_size() - 性能上和
stat()几乎无差别,但异常开销略高,高频调用场景慎用
try {
auto size = std::filesystem::file_size("data.bin");
return static_cast<long long>(size);
} catch (const std::filesystem::filesystem_error& e) {
// e.code().value() 给出具体 errno,如 ENOENT、EACCES
return -1;
}
选哪个?关键看你的使用上下文
如果已经用 ifstream 打开了文件,且确定只读一次、不关心并发修改,就地用 seekg/tellg 最轻量;如果只是查大小、不打算读内容,或者需要高可靠性(比如校验、预分配缓冲区),stat() 或 std::filesystem::file_size() 更合适。
容易被忽略的一点:所有方法都只返回“逻辑大小”,不等于磁盘占用(受块大小、稀疏文件、压缩属性影响)。如果你实际需要的是磁盘空间占用,得用 statfs(Unix)或 GetDiskFreeSpaceEx()(Windows)——那完全是另一个问题了。


















