c++oding="utf-8" ?>
windows需用createfile以generic_write打开文件,setfiletime传utc时间;linux/macos推荐utimensat并用utime_omit/utime_now;c++跨平台须条件编译,注意libstdc++旧版本不支持std::filesystem::last_write_time写入。

Windows 下用 SetFileTime 修改文件时间戳
Windows API 提供了精确控制文件时间戳的能力,但必须注意:需要以写权限打开文件句柄,且不能直接对路径操作。常见错误是传入只读路径或没处理时区——SetFileTime 要求 FILETIME 是 UTC 时间,本地时间不转换会导致时间偏移 8 小时(或对应时区差)。
实操建议:
- 用
CreateFile打开文件,标志必须含GENERIC_WRITE,且不能加FILE_ATTRIBUTE_READONLY - 调用
SystemTimeToFileTime前,先用TzSpecificLocalTimeToSystemTime把本地时间转为 UTC - 三个时间(创建、访问、修改)可单独设为
NULL,表示不修改该项 - 修改后记得
CloseHandle,否则句柄泄漏
// 示例:把 file.txt 的修改时间设为 2024-01-01 12:00:00
SYSTEMTIME st = {2024,1,0,1,12,0,0,0};
FILETIME ft;
TzSpecificLocalTimeToSystemTime(NULL, &st, &st);
SystemTimeToFileTime(&st, &ft);
HANDLE h = CreateFile(L"file.txt", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
SetFileTime(h, NULL, NULL, &ft); // 只改最后写入时间
CloseHandle(h);
Linux/macOS 下用 utimes 或 utimensat
utimes 简单但只能到微秒精度,且不支持纳秒;现代代码应优先用 utimensat,它支持纳秒、可指定是否跟随符号链接、还能相对路径操作。容易踩的坑是传入空指针导致时间被设为当前时间——哪怕你只想改一个时间字段,也要显式填好两个字段(tv_sec 和 tv_nsec),未设置项填 UTIME_OMIT。
实操建议:
- 时间结构用
struct timespec[2]:索引 0 是访问时间,索引 1 是修改时间 - 想保持某时间不变,对应位置填
{.tv_sec = UTIME_OMIT};想设为 now,填{.tv_sec = UTIME_NOW} - 路径用相对路径时,第一个参数传
AT_FDCWD;要避免竞态,加AT_SYMLINK_NOFOLLOW -
utimes接受struct timeval[2],但已不推荐用于新项目
// 示例:仅修改 file.txt 的 mtime 为 2024-01-01 12:00:00.123456789
struct timespec ts[2] = {
{.tv_sec = UTIME_OMIT}, // atime 不变
{.tv_sec = 1704110400, .tv_nsec = 123456789} // mtime
};
utimensat(AT_FDCWD, "file.txt", ts, AT_SYMLINK_NOFOLLOW);
C++ 跨平台封装要注意的兼容性点
没有标准库函数能直接改时间戳,所以跨平台封装必须条件编译。别依赖 std::filesystem::last_write_time 的 setter——它在 libstdc++(GCC)里直到 GCC 13 才真正支持写入,在旧版本中会静默失败或抛 std::filesystem::filesystem_error 且无提示。
实操建议:
- 检查编译器+标准库组合:
__GLIBCXX__版本 last_write_time 写入不可靠 - Windows 路径要用宽字符(
wchar_t*),Linux/macOS 必须用 UTF-8 编码的char*,混用会出错 - 不要假设
time_t是秒级——Windows 的FILETIME是 100 纳秒单位,Linux 的timespec.tv_nsec是纳秒,换算时别丢精度 - 修改系统时间需要管理员/root 权限,普通用户只能改自己有写权限的文件
修改时间戳失败时最常被忽略的原因
错误往往不报具体原因,只返回 false 或 -1。最容易漏查的是文件系统挂载选项:noatime 或 relatime 会让访问时间(atime)无法更新;某些 NFS 或 FAT32 分区根本不支持修改创建时间(ctime)——它由内核在 inode 创建时硬写死,任何 API 调用都无效。
排查建议:
- 先用命令行验证:
touch -m -d "2024-01-01" file.txt,如果命令也失败,问题在环境而非代码 - 检查
stat file.txt输出中的Access:、Modify:、Change:字段能否被 touch 改动 - Windows 上用
fsutil behavior query disablelastaccess查 atime 是否被禁用 - 对只读文件系统或容器挂载卷,即使有 root 权限也无法修改时间戳
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











