Сбой DeleteFile в недавно закрытом файле - PullRequest
8 голосов
/ 18 ноября 2009

У меня есть однопоточная программа (C ++, Win32, NTFS), которая сначала создает довольно длинный временный файл, закрывает его, открывает для чтения, читает, снова закрывает и пытается удалить, используя DeleteFile().

Обычно все идет гладко, но иногда DeleteFile() не удается, и GetLastError() возвращает ERROR_ACCESS_DENIED. Файл не только для чтения наверняка. Это происходит с файлами любого размера, но вероятность увеличивается с размером файла.

Есть идеи, что может быть блокировка файла? Я попробовал проверить инструменты WinInternals и не нашел ничего подозрительного.

Ответы [ 7 ]

10 голосов
/ 18 ноября 2009

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.                                          
*/
9 голосов
/ 18 ноября 2009

Просто дикая догадка - у вас установлено антивирусное программное обеспечение? Вы пытались отключить какие-либо функции защиты в реальном времени, если вы это делаете?

4 голосов
/ 18 ноября 2009

Добавьте вызов MessageBox () перед вызовом DeleteFile (). Когда он появится, запустите инструмент sysinternals Process Explorer. Найдите открытый дескриптор файла. По всей вероятности, вы не закрыли все дескрипторы файла ...

3 голосов
/ 18 ноября 2009

Я полагаю, что это покрыто 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;
}
1 голос
/ 16 мая 2018

У вас может быть состояние гонки. 1. Операционная система запрашивается для записи данных. 2. Операционная система просит закрыть файл. Это вызывает окончательную очистку буфера. Файл не будет закрыт, пока не будет выполнена очистка буфера. Тем временем ОС вернет управление программе, работая над очисткой буфера. 3. Операционная система запрашивает удаление файла. Если очистка еще не завершена, файл все равно будет открыт и запрос отклонен.

1 голос
/ 18 ноября 2009

Может быть, изменения все еще кэшированы и еще не сохранены?

Вы можете проверить это, добавив WaitForSingleObject на дескриптор файла, чтобы быть уверенным.

0 голосов
/ 27 августа 2012
#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;
}  
...