Linux文件系统不存储创建时间,stat()无st_birthtim,statx()也不返回birth time;可靠时间仅有mtime、atime、ctime;需创建时间须自行记录到xattr或数据库。

Linux 下无法获取文件创建时间,别白费劲了
Linux 文件系统(ext4、XFS 等)普遍不存储 birth time(即创建时间),stat() 返回的 st_birthtim 字段在 glibc 中压根未定义,调用 statx() 也可能返回 ENODATA。你看到的 “创建时间” 很可能是某些工具伪造的(比如取 st_ctim 并标注为 birth),实际不可靠。
能稳定拿到的是:
-
st_mtim:最后修改时间(mtime) -
st_atim:最后访问时间(atime),但默认挂载常带relatime或noatime,真实访问可能不更新 -
st_ctim:状态变更时间(ctime),如权限、硬链接数、所有者变化——不是创建时间
若真需创建时间,唯一可行路径是:在写入文件时主动记录时间戳到扩展属性(xattr)或外部元数据库,而非依赖内核。
用 statx() 读取纳秒级 atime/mtime/ctime(含微秒精度)
statx() 是 Linux 4.11+ 引入的系统调用,支持纳秒精度和显式字段控制,比传统 stat() 更可靠。注意它不返回创建时间,但能给出真正的微秒级(其实是纳秒,截断即可)访问与修改时间。
关键点:
- 必须用
AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW避免意外跟随符号链接或触发 automount - 填
STATX_ATIME | STATX_MTIME | STATX_CTIME到mask,否则对应字段为 0 -
stx_atime.tv_nsec是纳秒部分,除以 1000 即得微秒;整数秒部分在stx_atime.tv_sec - 需检查
stx_mask & STATX_ATIME是否成立,某些文件系统或挂载选项下 atime 可能不可用
#include <sys>
#include <fcntl.h>
#include <stdio.h><p>struct statx stx;
if (statx(AT_FDCWD, "/path/to/file", AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW,
STATX_ATIME | STATX_MTIME, &stx) == 0) {
if (stx.stx_mask & STATX_ATIME) {
long atime_us = stx.stx_atime.tv_sec * 1000000L + stx.stx_atime.tv_nsec / 1000;
printf("atime (μs): %ld\n", atime_us);
}
}</p></stdio.h></fcntl.h></sys>
macOS 上用 getattrlistbulk() 或 stat() 的 st_birthtimespec
macOS(APFS/HFS+)原生支持创建时间,可通过 stat() 直接读取:st_birthtimespec.tv_sec 和 st_birthtimespec.tv_nsec。这是少数能真正拿到可靠创建时间的主流系统。
但要注意:
-
stat()在 macOS 上已扩展支持st_birthtimespec,无需额外系统调用 - 某些 NFS 挂载或旧版卷可能不填充该字段,需检查
st_birthtimespec.tv_sec != 0且tv_nsec != -1 - 如果需更高精度批量获取(如目录遍历),可用
getattrlistbulk(),但接口复杂、文档少,日常开发优先用stat()
示例判断是否有效:
struct stat sb;
if (stat("/path/to/file", &sb) == 0) {
if (sb.st_birthtimespec.tv_sec != 0 || sb.st_birthtimespec.tv_nsec != -1) {
long birth_us = sb.st_birthtimespec.tv_sec * 1000000L + sb.st_birthtimespec.tv_nsec / 1000;
}
}
跨平台 C++ 封装建议:别抽象“创建时间”,按系统分叉处理
试图写一个统一接口返回“创建时间”的封装,大概率会掩盖行为差异、引发隐性 bug。更务实的做法是明确区分能力边界:
- Linux:只暴露
last_access_time()和last_write_time(),内部用statx();明确文档注明无创建时间 - macOS:提供
creation_time(),基于stat()的st_birthtimespec - Windows:用
GetFileInformationByHandle()读ftCreationTime,注意转为 Unix 时间戳时考虑时区与 100ns 单位
微秒级精度本身不难实现(所有平台都支持纳秒/100ns 级原始值),难点永远在语义一致性——st_ctime 在 Linux 是“元数据变更”,在 macOS 是“创建”,名字一样,含义不同。直接暴露底层字段名(如 st_atim)比包装成 created_at() 更诚实。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











