MoveFile移动文件后,原位置新建同名文件创建时间未重置问题
解决MoveFile后创建同名文件继承原创建时间的问题
问题重现
调用MoveFile将文件移动到新目录后,立刻在原位置创建同名新文件,期望新文件创建时间为当前时刻,但实际始终沿用原文件的创建时间。调试或在移动与打开操作间添加sleep时,新文件创建时间显示正常。尝试过SetFileTime但未生效,文件已成功移动,原位置在执行打开操作前无该文件。
代码示例:FILE* m_pFile; ::MoveFile(bstrRequestedFile, bstrTimestampLogFile); m_pFile = ::_wfsopen(bstrRequestedFile, L"wt", _SH_DENYNO);
原因分析
这是Windows NTFS文件系统的MFT记录复用机制导致的:当文件被移动或删除后,NTFS不会立即回收对应的主文件表(MFT)记录,而是将其标记为可用状态。如果短时间内在同一路径创建同名文件,系统会复用这条旧的MFT记录,导致新文件直接继承原文件的创建时间。调试或sleep时,系统有足够时间完成MFT记录的清理,新文件会生成全新的记录,时间自然显示正常。
解决方案
方案1:强制MoveFile操作立即落地
使用MoveFileEx替代MoveFile,并指定MOVEFILE_WRITE_THROUGH标志,强制系统将移动操作的元数据写入磁盘,减少文件系统缓存延迟,降低MFT复用的概率:
FILE* m_pFile; BOOL moveSuccess = ::MoveFileEx(bstrRequestedFile, bstrTimestampLogFile, MOVEFILE_WRITE_THROUGH); if (!moveSuccess) { // 处理移动失败逻辑,可调用GetLastError()排查具体问题 return; } m_pFile = ::_wfsopen(bstrRequestedFile, L"wt", _SH_DENYNO);
方案2:显式设置新文件的创建时间(最可靠)
不管是否复用MFT记录,直接强制设置新文件的创建时间为当前时刻,有两种实现方式:
方式A:用CreateFile直接创建并设置时间
使用底层CreateFile函数创建文件,配合CREATE_NEW标志确保文件不存在时才创建,之后调用SetFileTime设置时间:
HANDLE hFile = ::CreateFileW( bstrRequestedFile, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_NEW, // 严格要求文件不存在才创建,避免意外覆盖 FILE_ATTRIBUTE_NORMAL, NULL ); if (hFile != INVALID_HANDLE_VALUE) { FILETIME currentTime; ::GetSystemTimeAsFileTime(¤tTime); // 同时设置创建、访问、修改时间为当前时间 ::SetFileTime(hFile, ¤tTime, ¤tTime, ¤tTime); // 若需要继续用FILE*操作,可转成标准文件指针 FILE* m_pFile = ::_wfdopen(hFile, L"wt"); // ...后续文件读写操作 } else { // 处理创建失败,调用GetLastError()获取错误码排查问题 }
方式B:在_wfsopen后设置时间
如果坚持使用_wfsopen,可以通过_get_osfhandle获取底层文件句柄,再调用SetFileTime:
FILE* m_pFile = ::_wfsopen(bstrRequestedFile, L"wt", _SH_DENYNO); if (m_pFile != NULL) { // 获取底层文件句柄 HANDLE hFile = (HANDLE)_get_osfhandle(_fileno(m_pFile)); if (hFile != INVALID_HANDLE_VALUE) { FILETIME currentTime; ::GetSystemTimeAsFileTime(¤tTime); // 仅设置创建时间,访问和修改时间保持默认(也可一并设置) ::SetFileTime(hFile, ¤tTime, NULL, NULL); } }
说明:之前调用SetFileTime未生效,大概率是因为没有正确获取文件句柄,或者未检查函数返回值排查错误(比如调用时机不对、权限不足等)。
内容的提问来源于stack exchange,提问作者cab327
相关产品推荐
相关产品推荐

