Если вы столкнулись с этой проблемой при использовании Maven , вы можете скомпилировать свой код с помощью подключаемого модуля Maven Compiler .
org.apache.maven.plugins
maven-compiler-plugin
3.1
1.6
.....
UPDATE: установите source
и target
на 1.8
, если вы используете JDK 8.
Почему вы не первый раз переименовываете удаляемый файл, а затем удаляете его?
Используйте GetTempFileName()
для получения уникального имени, затем используйте MoveFile()
для переименования файла. Затем удалите переименованный файл. Если фактическое удаление действительно асинхронно и может конфликтовать с созданием одного и того же файла (как показывают ваши тесты), это должно решить проблему.
Редактирование: Конечно, если ваш анализ прав, и файловые операции происходят несколько асинхронно, это может привести к проблеме, которую вы пытаетесь удалить файл до того, как будет выполнено переименование. Но тогда вы всегда можете попытаться удалить фоновый поток.
Редактировать # 2: Если Ганс прав (и я склонен верить его анализу), то перемещение может не помочь, потому что вы не сможете фактически переименовать файл, открытый другим процессом. (Но тогда вы могли бы, я не знаю этого.) Если это действительно так, единственный способ, который я могу придумать, - «продолжать пытаться». Вам придется подождать несколько миллисекунд и повторить попытку. Храните тайм-аут, чтобы отказаться, когда это не поможет.
Согласно [1], вы можете использовать NtDeleteFile
, чтобы избежать асинхронного характера DeleteFile. Кроме того, [1] дает некоторые подробности о том, как работает DeleteFile.
К сожалению, официальная документация на NtDeleteFile
[2] не содержит конкретных подробностей по этой проблеме.
[1 ] http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FFile%2FNtDeleteFile.html [2] https: // msdn .microsoft.com / EN-US / библиотека / окна / оборудование / ff566435 (v = vs.85) .aspx
NtDeleteFile
только делает настройку удаления более эффективной, пропуская двухступенчатую последовательность NtOpenFile
, NtSetInformationFile
и не требуя, чтобы менеджер ввода-вывода выделил реальный объект File. Конечно, ему все же приходится выделять IRP для запроса заданной информации и вызывать драйвер файловой системы, и, конечно, файл все равно не будет отсоединен до тех пор, пока последняя ссылка на файл не будет закрыта / очищена.
– eryksun
11 April 2018 в 10:18
Глупое предложение - так как он не так редки, как насчет того, чтобы просто ждать несколько миллисекунд при неудаче и повторять попытку? Или, если важна латентность, переключитесь на другое имя файла, в результате чего старый файл будет удален позже.
Используйте функцию GetFileInformationByHandleEx с структурой FILE_STANDARD_INFO .
Но функция не может решить вашу проблему. @ sbi.
Возможно, я опаздываю на вечеринку, но в Vista / Win7 есть DeleteFileTransacted, который удаляет файл с помощью транзакций, которые гарантируют их удаление (очищает буферы файлов и т. д.). Для совместимости с XP это еще не вариант.
Еще одна идея, как это можно сделать, - это OpenFile с флагом OF_CREATE, который устанавливает длину до нуля, если файл существует, или создает его, если он этого не делает, а затем вызывает FlushFileBuffers в дескрипторе файла, чтобы дождаться завершения этой операции (создания нулевой длины файла). По завершении файл имеет размер 0, а затем просто вызывает DeleteFile.
Вы можете позже проверить, существует ли файл или если он имеет нулевую длину, чтобы обработать его таким же образом.
Возможно, это не ваша конкретная проблема, но ее возможное, поэтому я предлагаю вам выйти из Process Monitor (sysinternals) и посмотреть.
У меня была точно такая же проблема, и я обнаружил, что Comodo Internet Security способствовала этой проблеме. Раньше у меня была двухъядерная машина, но когда я впервые перешел на Intel i7, мое работающее программное обеспечение (jam.exe от программного обеспечения Perfore) больше не работало, потому что оно имело один и тот же шаблон (затем удаление создается, но без проверки). После отладки проблемы я обнаружил, что GetLastError () возвратил доступ, но обработчик процесса обнаруживает «отложенное удаление». Вот трассировка:
10:39:10.1738151 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Desired Access: Read Attributes, Delete, Disposition: Open, Options: Non-Directory File, Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a, OpenResult: Opened
10:39:10.1738581 AM jam.exe 5032 QueryAttributeTagFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Attributes: ANCI, ReparseTag: 0x0
10:39:10.1738830 AM jam.exe 5032 SetDispositionInformationFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Delete: True
10:39:10.1739216 AM jam.exe 5032 CloseFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1739438 AM jam.exe 5032 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1744837 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1788811 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1838276 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1888407 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1936323 AM System 4 FASTIO_ACQUIRE_FOR_SECTION_SYNCHRONIZATION C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS SyncType: SyncTypeOther
10:39:10.1936531 AM System 4 FASTIO_RELEASE_FOR_SECTION_SYNCHRONIZATION C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1936647 AM System 4 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1939064 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat DELETE PENDING Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0
10:39:10.1945733 AM cmdagent.exe 1188 CloseFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1946532 AM cmdagent.exe 1188 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1947020 AM cmdagent.exe 1188 IRP_MJ_CLOSE C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS
10:39:10.1948945 AM cfp.exe 1832 QueryOpen C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat FAST IO DISALLOWED
10:39:10.1949781 AM cfp.exe 1832 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat NAME NOT FOUND Desired Access: Read Attributes, Disposition: Open, Options: Open Reparse Point, Attributes: n/a, ShareMode: Read, Write, Delete, AllocationSize: n/a
10:39:10.1989720 AM jam.exe 5032 CreateFile C:\Users\Dad\AppData\Local\Temp\jam5032t1.bat SUCCESS Desired Access: Generic Write, Read Attributes, Disposition: OverwriteIf, Options: Synchronous IO Non-Alert, Non-Directory File, Attributes: N, ShareMode: Read, Write, AllocationSize: 0, OpenResult: Created
Как вы можете видеть, есть запрос на удаление, за которым следуют несколько попыток снова открыть файл с помощью jam.exe (его fopen в цикле). Вы можете видеть, что cmdagent.exe предположительно имел открытый файл, когда он закрывает свой дескриптор, а затем вдруг jam.exe теперь может открыть файл.
Конечно, предлагаемое решение ждать и повторять попытку, работает просто отлично.
В Windows есть другие процессы, которые хотят часть этого файла. Индекс поиска является очевидным кандидатом. Или вирусный сканер. Они откроют файл для полного доступа, в том числе FILE_SHARE_DELETE, так что другие процессы не будут сильно зависеть от их открытия файла.
Это обычно хорошо работает, если вы не создаете / не записываете / не удаляете высокий уровень. Удаление будет успешным, но файл не сможет исчезнуть из файловой системы, пока последний дескриптор не будет закрыт. Ручка удерживается, скажем, поисковым индексом. Любая программа, которая пытается открыть этот файл ожидающего удаления, будет удалена с ошибкой 5.
В противном случае это общая проблема в многозадачной операционной системе, вы не можете знать, какой другой процесс может понадобиться для работы с вашими файлами , Ваша модель использования кажется необычной, сначала проверьте это. Обходным путем было бы уловить ошибку, спать и повторить попытку. Или перемещение файла в корзину с помощью SHFileOperation ().
Поскольку вы создаете новый файл, обрабатываете его, а затем удаляете его, это звучит так, как будто вы care не знаете, что такое имя файла. Если это действительно так, вам следует всегда подумать о создании временного файла . Таким образом, каждый раз через этот процесс вам не нужно care , чтобы файл еще не удалился.
Я думаю, что это просто плохой дизайн в файловой системе. Я видел ту же проблему, когда работал с коммуникационными портами, открывая / закрывая их.
К сожалению, я думаю, что самым простым решением было бы просто повторить попытку создания файла несколько раз, если вы получите INVALID_HANDLE_VALUE
. GetLastError()
может также дать вам лучший способ обнаружения этого конкретного INVALID_HANDLE_VALUE
.
Я предпочел бы перекрытие ввода-вывода, но там CloseHandle()
и DeleteFile()
не обрабатывают перекрывающиеся операции: ([/ д2]
У меня на самом деле была такая же проблема при использовании LoadLibrary ( path ). Я не смог удалить файл в пути .
Решение заключалось в том, чтобы «закрыть дескриптор» или использовать метод FreeLibrary ( path ).
ПРИМЕЧАНИЕ. Пожалуйста, прочитайте «Замечания» на MSDN относительно FreeLibrary ().
Если CreateFile возвращает INVALID_HANDLE_VALUE, тогда вы должны определить, что GetLastError возвращает в вашей конкретной ситуации (ожидающее удаления), и возвратить его обратно в CreateFile только на основе этого кода ошибки.
Изменить
Флаг FILE_FLAG_DELETE_ON_CLOSE вас купит?
GetLastError()
.
– sbi
21 September 2010 в 21:41
GetTempFileName()
имеет i> для создания файла, иначе файл с одинаковым именем может быть создан кем-то еще между временем, когда вы получите уникальное имя файла и когда вы действительно создаете файл. В любом случае, рад, что вы его работали. – sbi 22 September 2010 в 17:17