C++file_size获取文件大小字节
C++里怎么靠谱地拿到文件大小?别再用stat或fstream绕弯了
上周帮同事查一个日志切割异常,发现他用std::ifstream配合seekg(0, std::ios::end)再tellg()算文件大小,结果在Windows上遇到空文件返回-1、中文路径直接失败、大文件(>2GB)在32位编译下溢出……最后兜了一圈才想起:C++17早就把这事干得挺稳了。
没错,std::filesystem::file_size() 就是专治这类“小而烦”的标准解法。它不依赖平台API封装,不碰流状态机,也不需要你手动处理符号链接或权限异常——它就做一件事:返回一个std::uintmax_t类型的字节数,干净利落。
但光贴一行代码没用。真正在项目里用,你会撞上几个具体问题:路径传进去却抛filesystem_error;明明文件存在却报“no such file or directory”;或者更隐蔽的——软链接没解引用,拿到的是链接文件本身的大小,不是目标文件的。
先看最简可用写法:
#include <filesystem>
#include <iostream>
namespace fs = std::filesystem;
int main() {
try {
auto size = fs::file_size("config.json");
std::cout << "文件大小:" << size << " 字节\n";
} catch (const fs::filesystem_error& e) {
std::cerr << "获取失败:" << e.what() << '\n';
}
}
这里的关键不是语法,而是异常类型必须捕获 fs::filesystem_error,而不是笼统的 std::exception。因为file_size只会在路径不存在、无权限、跨文件系统挂载点不可达等真正语义错误时抛这个异常;而像磁盘满、I/O中断这类底层错误,它压根不负责——这恰恰是设计清醒的地方:它只管“逻辑可见性”,不管“瞬时可用性”。
那路径怎么传才少踩坑?
绝对路径最省心,相对路径务必确认当前工作目录是你以为的那个。别信IDE终端里pwd显示的路径——CMake构建、VS调试器、systemd服务启动,工作目录可能各不相同。稳妥做法是:用fs::absolute(path)兜底,或者干脆从可执行文件所在目录出发拼接:
auto exe_path = fs::canonical(fs::current_path() / "config.json"); // 更鲁棒
// 或者直接
auto config_path = fs::current_path() / "data" / "cache.bin";
注意/操作符是重载过的,比字符串拼接安全得多,自动处理路径分隔符差异。
另一个容易被忽略的点:符号链接默认不解引用。比如你有个log -> /var/log/app.log,file_size("log")返回的是链接文件本身(通常几十字节),不是目标日志的大小。要得到真实大小,得加个flag:
auto size = fs::file_size("log", fs::symlink_option::follow);
但别滥用follow——如果业务逻辑本就需要区分链接和实体(比如备份工具要保留链接结构),那就该用fs::is_symlink()先判断,再决定是否跟进。
还有人问:“大文件会不会卡住?”
不会。file_size底层调用的是系统stat()族函数(Linux/macOS)或GetFileAttributesEx()(Windows),本质是一次元数据读取,和文件内容完全无关。读1KB和读1TB的耗时几乎一样,都是纳秒级。
顺带提一句冷知识:file_size对目录也有效——它返回的是该目录项占用的磁盘空间(通常是4KB或8KB,取决于文件系统块大小),不是里面所有文件的总和。这点和du -s完全不同,别混淆。
最后说个实战细节:别在循环里反复调file_size查变化。比如轮询监控日志增长,每秒调一次,看似简单,实则浪费系统调用。更好的做法是fs::last_write_time()配合增量计算,或者直接用inotify/ReadDirectoryChangesW这类事件机制——file_size只适合“快照式”获取,不是监控探针。
总结下来,用好file_size就三件事:
✅ 包对头文件 <filesystem>,编译加 -std=c++17(GCC/Clang)或 /std:c++17(MSVC)
✅ 用 try/catch fs::filesystem_error 捕异常,别吞掉具体原因
✅ 路径用 fs::path 构造,链接按需加 follow,目录大小别当总和用
它不是万能钥匙,但在这个场景里,就是最短路径。写代码有时候就得承认:标准库已经把路铺平了,我们只需看清路标,别非绕去翻stat手册。


还没有评论,来说两句吧...