Solved:
- 可行的解决方案:履行机构的答复 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764298#3764298
- 对实际发生情况的解释:汉斯的回答 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764322#3764322
- 为什么OpenFile没有通过“DELETE PENDING”的解释:本杰明的回答 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3776438#3776438
问题:
我们的软件在很大程度上是专有脚本语言的解释器引擎。该脚本语言能够创建文件、处理文件,然后删除文件。这些都是单独的操作,并且在这些操作之间没有文件句柄保持打开状态。
(即在文件创建期间,创建一个句柄,用于写入,然后关闭。在文件处理部分期间,一个单独的文件句柄打开文件,从中读取文件,并在 EOF 处关闭。并且finally,删除使用::DeleteFile,它只使用文件名,根本不使用文件句柄)。
最近我们开始意识到,特定的宏(脚本)有时无法在随后的某个随机时间创建文件(即,它在“创建、处理、删除”的前一百次迭代期间成功,但是当它出现时)回到创建它一百零一次,Windows 回复“访问被拒绝”)。
更深入地研究这个问题,我编写了一个非常简单的程序,它循环如下所示:
while (true) {
HANDLE hFile = CreateFileA(pszFilename, FILE_ALL_ACCESS, FILE_SHARE_READ,
NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
return OpenFailed;
const DWORD dwWrite = strlen(pszFilename);
DWORD dwWritten;
if (!WriteFile(hFile, pszFilename, dwWrite, &dwWritten, NULL) || dwWritten != dwWrite)
return WriteFailed;
if (!CloseHandle(hFile))
return CloseFailed;
if (!DeleteFileA(pszFilename))
return DeleteFailed;
}
正如您所看到的,这是直接针对 Win32 API 的,并且非常简单。我创建一个文件,写入它,关闭句柄,删除它,冲洗,重复......
但在某个地方,我会在 CreateFile() 调用期间收到 Access Denied (5) 错误。查看 sysinternal 的 ProcessMonitor,我可以看到根本问题是当我尝试再次创建文件时,该文件上有一个待删除的文件。
问题:
- 有没有办法等待删除完成?
- 有没有办法检测文件是否正在等待删除?
我们尝试了第一个选项,即在 HFILE 上简单地使用 WaitForSingleObject()。但 HFILE 始终在 WaitForSingleObject 执行之前关闭,因此 WaitForSingleObject 始终返回 WAIT_FAILED。显然,尝试等待关闭句柄是行不通的。
我可以等待该文件所在文件夹的更改通知。但是,对于偶尔出现问题的问题来说,这似乎是一种极其耗费资源的混乱(也就是说:在我的 Windows 7 x64 E6600 PC 上进行的测试中,通常会出现问题)在迭代 12000+ 时失败——在其他机器上,它可能会在迭代 7、15 或 56 时发生,或者永远不会发生)。
我无法辨别任何明确允许这种以太的 CreateFile() 参数。无论 CreateFile 有什么参数,打开文件确实是不行的any当文件待删除时访问。
由于我可以在 Windows XP 机器和 x64 Windows 7 机器上看到此行为,因此我非常确定这是 Microsoft “按照预期”的核心 NTFS 行为。因此,我需要一个解决方案,允许操作系统在我尝试继续之前完成删除,最好不要不必要地占用 CPU 周期,并且不会产生监视该文件所在文件夹的巨大开销(如果可能)。
1 https://stackoverflow.com/questions/3764072/c-win32-how-to-wait-for-a-pending-delete-to-complete/3764298#3764298是的,此循环在写入失败或关闭泄漏失败时返回,但由于这是一个简单的控制台测试应用程序,因此应用程序本身会退出,并且 Windows 保证在进程完成时操作系统会关闭所有句柄。所以这里不存在泄漏。
bool DeleteFileNowA(const char * pszFilename)
{
// Determine the path in which to store the temp filename
char szPath[MAX_PATH];
strcpy(szPath, pszFilename);
PathRemoveFileSpecA(szPath);
// Generate a guaranteed to be unique temporary filename to house the pending delete
char szTempName[MAX_PATH];
if (!GetTempFileNameA(szPath, ".xX", 0, szTempName))
return false;
// Move the real file to the dummy filename
if (!MoveFileExA(pszFilename, szTempName, MOVEFILE_REPLACE_EXISTING))
return false;
// Queue the deletion (the OS will delete it when all handles (ours or other processes) close)
if (!DeleteFileA(szTempName))
return false;
return true;
}