windows不提供微秒级最后访问时间,getfiletime和getfileinformationbyhandleex均以100纳秒为单位,但受ntfs延迟写入和disablelastaccess策略影响,实际精度远低于理论值;精确监控需用etw或minifilter驱动。

Windows API 的 GetFileTime 最高只到 100 纳秒,但实际精度受文件系统限制
NTFS 卷上,GetFileTime 返回的 FILETIME 结构理论上是 100 纳秒单位(即 0.1 微秒),但 Windows 不会把每次访问都写入磁盘——默认禁用最后访问时间更新(LastAccessTime),且即使启用,NTFS 也会延迟写入、批量合并,导致你读到的时间可能滞后数秒甚至更久。
实操建议:
- 先确认是否已启用最后访问时间更新:
fsutil behavior query disablelastaccess;返回disablelastaccess = 1表示关闭(默认),需管理员权限运行fsutil behavior set disablelastaccess 0并重启资源管理器或机器 -
GetFileTime本身不区分“访问是否真实发生”,只要系统内核标记了访问(比如CreateFile带FILE_FLAG_NO_BUFFERING可能绕过),就可能触发更新 - 不要依赖
LastAccessTime做精确行为审计——它不是实时日志,而是粗粒度提示
用 GetFileInformationByHandleEx + FileBasicInfo 是更可靠的选择
相比老式 GetFileTime,这个函数支持直接读取内核维护的原始时间戳,且在启用了 disablelastaccess = 0 的 NTFS 上,能反映更接近真实的访问时机(仍非微秒级实时,但抖动更小)。
关键点:
- 必须用
HANDLE打开文件,且CreateFile需带FILE_READ_ATTRIBUTES权限 -
FileBasicInfo结构里的LastAccessTime字段仍是FILETIME类型,单位 100 纳秒,但数据来源更“新鲜” - 若打开失败并报错
ERROR_INVALID_PARAMETER,大概率是传入的缓冲区大小不对:必须严格为sizeof(FILE_BASIC_INFO) - 该函数在 Windows 8+ 和 Server 2012+ 才完全支持;旧系统会失败,需回退到
GetFileTime
想真正拿到微秒级访问记录?得换思路:用 ETW 或 Minifilter
Windows 内核本身不向用户态暴露“某次具体 read/write 操作发生的精确时间戳”。所谓“最后访问时间”,本质是文件对象被引用时由 I/O 管理器打的一个标记,不是硬件时钟采样点。
如果你真需要微秒级访问事件(比如监控某个 DLL 被加载的精确时刻),可行路径只有:
- ETW(Event Tracing for Windows):监听
Microsoft-Windows-Kernel-File提供的FileIoRead/FileIoWrite事件,其中TimeStamp字段精度可达微秒(取决于系统时钟分辨率,通常为 15.6ms,但高精度计时器启用后可到 ~1μs) - Minifilter 驱动:在 IRP_MJ_READ/IRP_MJ_WRITE 层拦截,用
KeQueryPerformanceCounter获取高精度时间戳,再通过通信机制传给用户态 - 别碰
FindFirstFileEx或 PowerShell 的Get-Item:它们底层还是调GetFileTime,精度和延迟没区别
C++ 示例:安全读取 LastAccessTime 的最小可行代码
下面这段代码避开常见坑(权限、结构体对齐、错误检查):
// 注意:需 #include <windows.h> & #pragma comment(lib, "kernel32.lib")
HANDLE h = CreateFile(L"test.txt", FILE_READ_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, OPEN_EXISTING, 0, nullptr);
if (h == INVALID_HANDLE_VALUE) { /* 处理错误 */ }
<p>FILE_BASIC_INFO info = {};
if (GetFileInformationByHandleEx(h, FileBasicInfo, &info, sizeof(info))) {
// info.LastAccessTime 是 100-nanosecond intervals since Jan 1, 1601 UTC
// 转成微秒:乘以 0.1,但注意 int64_t 溢出风险
LONGLONG us = info.LastAccessTime.QuadPart / 10; // 直接除 10 得微秒值
}
CloseHandle(h);
</p></windows.h>
容易漏掉的细节:结构体必须零初始化(否则未赋值字段可能含垃圾值),GetFileInformationByHandleEx 返回 FALSE 时务必用 GetLastError() 查原因,而不是假设失败=文件不存在。
微秒级“最后访问时间”本质上是个幻觉——Windows 不提供它,NTFS 也不保证它。你真正能拿到的,是一个带延迟、被聚合、受策略开关控制的近似值。要精确,就得进内核或用 ETW。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











