DeleteFile在最近关闭的文件上失败

时间:2009-11-18 02:20:32

标签: c++ file winapi delete-file

我有一个单线程程序(C ++,Win32,NTFS),它首先创建一个相当长的临时文件,关闭它,打开以进行读取,读取,再次关闭并尝试使用DeleteFile()删除。

通常情况顺利,但有时DeleteFile()失败,GetLastError()返回ERROR_ACCESS_DENIED。文件不是只读的。它发生在任何大小的文件上,但概率随文件大小而增加。

可能锁定文件的任何想法?我尝试使用WinInternals工具进行检查,发现没有任何可疑之处。

7 个答案:

答案 0 :(得分:10)

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.                                          
*/

答案 1 :(得分:9)

只是猜测 - 您是否安装了任何防病毒软件?您是否尝试过禁用其中的任何实时保护功能?

答案 2 :(得分:4)

在调用DeleteFile()之前添加一个MessageBox()调用,当它出现时,运行sysinternals工具Process Explorer。 搜索文件的打开句柄。很可能你还没有关闭文件的所有句柄......

答案 3 :(得分:3)

我相信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;
}

答案 4 :(得分:1)

也许这些更改仍然已缓存但尚未保存?

您可以通过在文件句柄上添加 WaitForSingleObject 来检查这一点,以确保。

答案 5 :(得分:1)

您可能有竞争条件。 1.要求操作系统写入数据。 2.要求操作系统关闭文件。这会提示最终缓冲区刷新。在缓冲区刷新完成之前,文件不会关闭。同时操作系统将在处理缓冲区刷新时将控制权返回给程序。 3.要求操作系统删除该文件。如果尚未完成刷新,则文件仍将打开,请求被拒绝。

答案 6 :(得分:-1)

#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;
}