c++oding="utf-8" ?>
最推荐使用c++17 std::filesystem::file_size:跨平台、不打开文件、支持大文件和utf-8路径,失败抛异常;windows专属场景可用_file_size(需_io.h,配对_open/_close);ifstream::tellg须以binary模式打开并检查状态。

用 _file_size 获取文件大小:Windows 专属,快但不跨平台
_file_size 是 Microsoft CRT 提供的非标准函数,仅在 Windows 下可用(需 <io.h></io.h>),它直接调用系统 API GetFileSize,绕过 C++ 流缓冲,因此极快且不依赖文件是否打开、光标位置或读写模式。
常见错误是把它当通用函数用在 Linux/macOS 编译环境,会报 undefined reference to `_file_size'。另外,它只接受文件描述符(int fd),不是文件名——必须先用 _open 打开文件才能用:
#include <io.h>
int fd = _open("data.bin", _O_RDONLY);
if (fd != -1) {
long size = _file_size(fd); // 成功返回字节数,失败返回 -1L
_close(fd);
}</io.h>
- 必须配对使用
_open/_close,不能混用fopen/fclose - 返回值类型是
long,对大于 2GB 的文件在 LLP64 环境(如 MSVC x64)下可能截断,建议检查是否为-1L并配合errno - 不支持 Unicode 路径(
_wopen可用,但_file_size仍只认 fd)
用 std::ifstream::tellg 获取大小:看似简单,实则陷阱密集
很多人试过:std::ifstream f("x.dat"); f.seekg(0, std::ios::end); auto sz = f.tellg(); —— 这在文本模式下可能出错,在二进制大文件上可能慢,甚至返回负值。
根本原因是:默认构造的 std::ifstream 以文本模式打开(std::ios::in),而文本模式会做行尾转换(CRLF → '\n'),导致 seekg(..., end) 的位置不可靠;tellg() 返回的是流内“逻辑位置”,不是真实字节数。
- 必须显式指定
std::ios::binary模式:std::ifstream f("x.dat", std::ios::binary); - 必须确保文件成功打开,否则
tellg()返回-1(std::streampos(-1)) - 调用
seekg(0, std::ios::end)后,要再调用一次seekg(0, std::ios::beg)才能继续读,否则流处于 EOF 状态 - 对某些特殊文件(如设备文件、管道、procfs 条目),
seekg可能失败并置位failbit
更可靠的选择:C++17 std::filesystem::file_size
这是目前最推荐的方式:标准、跨平台、不打开文件、不依赖流状态,且语义明确。
它底层在 Windows 调用 GetFileSizeEx,Linux/macOS 调用 stat,天然支持大文件(返回 uintmax_t)和 UTF-8 路径(只要 std::filesystem::path 构造正确)。
#include <filesystem>
namespace fs = std::filesystem;
try {
uintmax_t sz = fs::file_size("log.bin"); // 抛异常而非返回错误码
} catch (const fs::filesystem_error& e) {
// e.what() 包含具体原因,如 "No such file or directory"
}</filesystem>
- 不修改文件状态,无副作用,适合只读场景
- 不支持 stdin/stdout 等非路径资源(这点不如
_file_size(fd)或seekg) - MSVC 需启用 `/std:c++17` 且链接 `libcmt`(Debug 下注意 `/MDd` vs `/MTd`);GCC/Clang 需 `-lstdc++fs`(GCC
性能与选型建议:别为小文件过度优化
三者实际耗时差异在纳秒到微秒级,除非你在高频循环中查成千上万个文件大小,否则瓶颈从来不在这个函数本身。
- 写跨平台工具或长期维护项目 → 无条件选
std::filesystem::file_size - Windows 专用高性能服务,且已用 CRT 文件描述符管理 I/O →
_file_size更轻量 - 必须用
std::ifstream且已打开文件 → 用seekg+tellg,但务必加binary和错误检查
最容易被忽略的是:所有方法都对符号链接默认解析目标文件大小,而不是链接本身(std::filesystem::file_size 行为一致;若需链接自身大小,得用 std::filesystem::symlink_status 查 file_size 字段)。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











