正确姿势是先以binary模式打开文件并检查is_open(),再seekg(0,end)后立即检查fail(),仅当无错误时用tellg()获取大小并判断是否为0;需避免误将定位失败(如-1)当作空文件,且比较时保持streampos有符号性。

用 seekg 和 tellg 判断文件是否为空的正确姿势
直接调用 seekg(0, std::ios::end) 后再 tellg() 是常见做法,但必须检查 tellg() 是否返回 -1 —— 这表示定位失败(比如文件不可读、是设备文件或权限不足),此时不能当作“空文件”处理。
关键步骤顺序不能错:
- 先用
open()以std::ios::binary模式打开,避免文本模式下换行符影响位置计算 - 调用
seekg(0, std::ios::end)移动到末尾 - 立刻检查
fail()或bad():若为真,tellg()结果无效 - 只在无错误时才用
tellg()获取字节数,等于0才是真正空文件
ifstream 构造后不检查状态就调 seekg 的典型错误
很多代码直接写 std::ifstream f("test.txt"); f.seekg(0, std::ios::end);,但没验证 f 是否成功打开。如果文件不存在或无权限,seekg 不会抛异常,而是置位 failbit,后续 tellg() 返回 -1,容易被误判为“空”。
安全写法必须带状态校验:
立即学习“C++免费学习笔记(深入)”;
std::ifstream f("test.txt", std::ios::binary);
if (!f.is_open()) {
// 文件打不开,不是空,是错误
return false;
}
f.seekg(0, std::ios::end);
if (f.fail()) {
// seek 失败(例如 /dev/null、/proc/sys/kernel/osrelease 等特殊路径)
return false;
}
std::streampos size = f.tellg();
return size == 0;
为什么不用 stat()?跨平台和语义差异问题
在 Linux/macOS 上用 stat() 查 st_size 更快、更直接,但它不是 C++ 标准库功能,Windows 需用 GetFileSizeEx() 替代,维护成本高。更重要的是语义差异:stat() 返回的是文件系统元数据中的大小,而 seekg/tellg 走的是流 I/O 路径,对某些特殊文件(如 FIFO、终端、procfs 条目)可能返回不同结果甚至失败。
如果你明确只处理普通磁盘文件,且项目已用 POSIX 或 Windows API,stat() 或 GetFileSizeEx() 更可靠;但若代码需统一走 std::ifstream 流逻辑(比如后续还要读内容),坚持用 seekg/tellg 并做好错误分支处理更一致。
注意 tellg() 返回类型和符号问题
tellg() 返回 std::streampos,它通常是 long long 或类似有符号整数类型。比较时别写成 if (tellg() == 0u)(无符号),否则当返回 -1 时会被转成极大正数,导致逻辑反转。
正确比较方式只有两种:
-
size == 0(size是std::streampos类型,保持原类型比较) - 或显式转为整数并检查负值:
auto sz = static_cast<:streamoff>(size); if (sz
另外,某些老旧编译器或极小嵌入式标准库中,streampos 可能是类类型,重载了 ==,所以不要自行 cast 成 int 或 size_t 去比。










