2009-11-18 3 views
7

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

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

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

+0

Возможно, вы закрыли файл, прежде чем пытаться его удалить? Вы пропустили какие-либо ручки? – RageZ

+0

Как я уже сказал, я даже проверил это с помощью инструментов WinInternals. Все открытые соединены с закрытием, но удаление не выполняется. И добавление спального места на 1 секунду устраняет проблему. –

+0

Это могут быть окна, багги, но я сомневаюсь в этом.если добавление 'sleep' заставляет его работать, должно быть хорошо.^ – RageZ

ответ

1

Возможно, изменения все еще сохранены и еще не сохранены?

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

+3

Кэширование записи прозрачно для приложения. Это не должно вызывать изменения в поведении. –

4

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

+1

Вот с чего я начал. Нет ручек. Итак, я зарегистрировал весь доступ к файлу, и ничего особенного. –

+0

Это звучит как состояние гонки (возможно, порядка миллисекунды), поэтому, если вы не замораживаете все, вы не сможете воспроизвести ошибку таким образом. (Но попытка, безусловно, помогает сузить возможности.) – 2009-11-18 02:34:10

8

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

+3

Этот ответ полностью заслуживает того, чтобы быть прав. –

+0

О, я не знаю об этом. –

8

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.           
*/ 
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; 
} 
+0

Не произойдет ли это, если другой процесс открыл тот же файл, учитывая следующее описание из документации? «Если в файле имеются открытые дескрипторы, вызов завершается с ошибкой, если они не были открыты в режиме общего доступа FILE_SHARE_DELETE». –

+0

Да, поэтому я не рекомендовал закрывать дескриптор файла между записью и чтением. Создайте первый дескриптор с FILE_FLAG_DELETE_ON_CLOSE, а затем используйте ReOpenFile или DuplicateHandle, если вам действительно нужен дескриптор файла, у которого нет доступа на запись. –

+0

Возможно, сегодня я неспокойный, но разве это не проблема, если кто-то подлый откроет файл перед последним вызовом CreateFile? последний вызов будет по-прежнему терпеть неудачу. –

0
#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; 
} 
Смежные вопросы