我有一个单线程程序(C++、Win32、NTFS),它首先创建一个相当长的临时文件,关闭它,打开读取,读取,再次关闭并尝试使用DeleteFile()
.
通常它会顺利进行,但有时DeleteFile(
) 会失败,并GetLastError()
返回 ERROR_ACCESS_DENIED。文件肯定不是只读的。它发生在任何大小的文件上,但概率随着文件大小而增加。
有什么想法可能会锁定文件吗?我尝试使用 WinInternals 工具进行检查,并没有发现任何可疑之处。
我有一个单线程程序(C++、Win32、NTFS),它首先创建一个相当长的临时文件,关闭它,打开读取,读取,再次关闭并尝试使用DeleteFile()
.
通常它会顺利进行,但有时DeleteFile(
) 会失败,并GetLastError()
返回 ERROR_ACCESS_DENIED。文件肯定不是只读的。它发生在任何大小的文件上,但概率随着文件大小而增加。
有什么想法可能会锁定文件吗?我尝试使用 WinInternals 工具进行检查,并没有发现任何可疑之处。
Windows 因这个问题而臭名昭著。SQLite 通过每 100 毫秒重试一次删除操作来处理该问题,直到最大次数。
我相信,如果您确定没有打开的句柄,那么在您的实现中执行此操作会在防病毒软件等打开文件时为您省去一些麻烦。
作为参考,来自 SQLite 源的评论:
/*
** Delete the named file.
**
** Note that windows does not allow a file to be deleted if some other
** process has it open. Sometimes a virus scanner or indexing program
** will open a journal file shortly after it is created in order to do
** whatever it does. While this other process is holding the
** file open, we will be unable to delete it. To work around this
** problem, we delay 100 milliseconds and try to delete again. Up
** to MX_DELETION_ATTEMPTs deletion attempts are run before giving
** up and returning an error.
*/
只是一个疯狂的猜测-您是否安装了任何防病毒软件?您是否尝试过禁用其中的任何实时保护功能,如果您这样做了?
我相信这包含在Windows Internals中。简短的故事是,即使您在文件句柄上调用了 CloseHandle,内核可能仍然有未完成的引用,需要几毫秒才能关闭。
完成后删除文件的更可靠方法是在打开最后一个句柄时使用 FILE_FLAG_DELETE_ON_CLOSE 标志。如果您可以避免在读/写之间关闭文件,这会更好。
#include <windows.h>
#include <stdio.h>
int wmain(int argc, wchar_t** argv)
{
LPCWSTR fileName = L"c:\\temp\\test1234.bin";
HANDLE h1 = CreateFileW(
fileName,
GENERIC_WRITE,
// make sure the next call to CreateFile can succeed if this handle hasn't been closed yet
FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (h1 == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "h1 failed: 0x%x\n", GetLastError());
return GetLastError();
}
HANDLE h2 = CreateFileW(
fileName,
GENERIC_READ,
// FILE_SHARE_WRITE is required in case h1 with GENERIC_WRITE access is still open
FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
// tell the OS to delete the file as soon as it is closed, no DeleteFile call needed
FILE_FLAG_DELETE_ON_CLOSE | FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_TEMPORARY,
NULL);
if (h2 == INVALID_HANDLE_VALUE)
{
fprintf(stderr, "h2 failed: 0x%x\n", GetLastError());
return GetLastError();
}
return 0;
}
在调用 DeleteFile() 之前添加 MessageBox() 调用,当它出现时,运行 sysinternals 工具 Process Explorer。搜索文件的打开句柄。您很可能还没有关闭文件的所有句柄......
也许更改仍在缓存中并且尚未保存?
您可以通过在文件句柄上添加WaitForSingleObject来确定这一点。
您可能有竞争条件。1. 请求操作系统写入数据。2. 要求操作系统关闭文件。这会提示最终缓冲区刷新。在缓冲区刷新完成之前,不会关闭文件。同时,操作系统将在缓冲区刷新时将控制权返回给程序。3. 请求操作系统删除该文件。如果刷新尚未完成,则文件仍将打开并且请求被拒绝。
#include <iostream>
#include <windows.h>
int main(int argc, const char * argv[])
{
// Get a pointer to the file name/path
const char * pFileToDelete = "h:\\myfile.txt";
bool RemoveDirectory("h:\\myfile.txt");
// try deleting it using DeleteFile
if(DeleteFile(pFileToDelete ))
{
// succeeded
std::cout << "Deleted file" << std::endl;
}
else
{
// failed
std::cout << "Failed to delete the file" << std::endl;
}
std::cin.get();
return 0;
}