Linux/macOS用utimes()或utimensat()设时间戳,Windows用SetFileTime();跨平台需注意权限、时区、文件系统限制及精度差异,调试应直接读原始时间值验证。

Linux/macOS 下用 utimes() 或 utimensat() 设置时间戳
POSIX 系统(包括 Linux 和 macOS)不提供标准 C++ 接口修改文件时间戳,必须调用系统 API。utimes() 是较老但广泛支持的函数,接受 struct timeval[2],分别对应访问时间和修改时间;utimensat() 更现代,支持纳秒精度和相对路径,且能传 ATIME_NOW/MTIME_NOW 让内核自动填充。
常见错误是传入空指针或时间数组顺序颠倒——tv[0] 是访问时间(atime),tv[1] 是修改时间(mtime)。另外,普通用户无法将时间设为未来过久(如超过 24 小时),否则可能被内核截断或拒绝。
- 用
utimensat(AT_FDCWD, "file.txt", times, 0)最稳妥,times是struct timespec[2] - 若需兼容旧系统,用
utimes("file.txt", tv),注意tv是struct timeval* - 设置“现在”时间可直接传
NULL给utimes(),但utimensat()需显式用UTIME_NOW
Windows 下用 SetFileTime() 设置时间戳
Windows API 要求先用 CreateFile() 打开文件获取句柄,再调用 SetFileTime()。关键点在于:时间必须是 UTC 格式的 FILETIME(64 位,100 纳秒单位),不能直接用本地时间或 time_t;且三个时间(创建、访问、修改)必须同时传入,哪怕只改其中一个,其余两个得先用 GetFileTime() 读出来再复用。
容易踩的坑是忽略时区转换——SystemTimeToFileTime() 输入的是本地系统时间,而 SetFileTime() 内部按 UTC 处理,若程序运行在非系统默认时区(比如用 SetThreadLocale() 改过),结果会偏移。更可靠的做法是用 SystemTimeToTzSpecificLocalTime() 或直接基于 UTC 构造 SYSTEMTIME。
立即学习“C++免费学习笔记(深入)”;
- 必须以
GENERIC_WRITE权限打开文件,只读打开会失败 -
SetFileTime()返回FALSE时,用GetLastError()查具体原因,常见是权限不足或句柄无效 - 若只需修改 atime/mtime(不碰 ctime),传入的
LPFILETIME指针可以为NULL,但数组位置不能错位
C++ 跨平台封装要注意的底层差异
没有跨平台标准函数,自己封装时不能简单“if Linux / if Windows”。核心差异在于:Linux 的 atime 可能被挂载选项(如 noatime)禁用,即使调用成功也不生效;Windows 的 ctime(创建时间)一旦设置就不可更改(NTFS 限制),而 Linux 根本没有真正意义上的 ctime(stat::st_ctime 是状态变更时间,不是创建时间)。
另一个常被忽略的点是权限:Linux 下修改时间戳需要对文件有写权限(或 root),Windows 下需要 SE_BACKUP_NAME 特权才能修改任意文件(否则只能改自己拥有的文件)。普通应用应预判失败并降级处理,比如记录日志而不是崩溃。
- 不要依赖
std::filesystem::last_write_time()的 setter(C++17 提供)——它在 GCC/libstdc++ 中实际调用utimes(),但在 MSVC 中尚未完全实现,行为不一致 - 测试时务必在真实文件系统上运行,tmpfs 或某些容器卷(如 Docker bind mount)可能不支持时间戳更新
- 若需高精度(纳秒级),Linux 必须用
utimensat()+TIMESPEC,Windows 的FILETIME天然支持 100ns,但显示工具(如ls -la)通常只显示到秒或纳秒低三位
Python/Shell 调试时怎么快速验证时间戳是否真被改了
别只信 stat 命令输出——它默认显示“可读时间”,受 locale 和时区影响;也别用 ls -l,它只显示 mtime,且格式化后丢失精度。最可靠的方式是用 stat -c "%x %y %z" file.txt(Linux)或 stat -f "%Sa %Sm %Sc" -t "%Y-%m-%d %H:%M:%S" file.txt(macOS),直接输出原始 time_t 值或指定格式。
Windows 下用 powershell "(Get-Item 'file.txt').LastWriteTimeUtc" 查 UTC 时间,避免本地时区干扰。注意:即使 API 调用返回成功,也要检查输出值是否真的变了——有些文件系统(如 exFAT)只支持 2 秒精度,设 1 秒差会被四舍五入。
- 用
touch -d "2020-01-01 12:00" file.txt做基准对比,确认你的环境本身支持自定义时间 - 如果程序反复修改同一文件的时间戳,注意 ext4 默认启用
relatime,atime 更新会被延迟或合并,看起来像没生效 - 调试时加一句
sync();(Linux)或FlushFileBuffers(h)(Windows)确保元数据落盘,否则stat可能读到缓存旧值


















