Почему воссоздание папки, которая была удалена, когда она была открыта в проводнике Windows, не работает в WSH? [Дубликат]

Если вы столкнулись с этой проблемой при использовании Maven , вы можете скомпилировать свой код с помощью подключаемого модуля Maven Compiler .

 
        
            
                org.apache.maven.plugins
                maven-compiler-plugin
                3.1
                
                    1.6
                    1.6
                
            
       .....

UPDATE: установите source и target на 1.8, если вы используете JDK 8.

30
задан rmtheis 8 May 2015 в 04:12
поделиться

11 ответов

Почему вы не первый раз переименовываете удаляемый файл, а затем удаляете его?

Используйте GetTempFileName() для получения уникального имени, затем используйте MoveFile() для переименования файла. Затем удалите переименованный файл. Если фактическое удаление действительно асинхронно и может конфликтовать с созданием одного и того же файла (как показывают ваши тесты), это должно решить проблему.

Редактирование: Конечно, если ваш анализ прав, и файловые операции происходят несколько асинхронно, это может привести к проблеме, которую вы пытаетесь удалить файл до того, как будет выполнено переименование. Но тогда вы всегда можете попытаться удалить фоновый поток.

Редактировать # 2: Если Ганс прав (и я склонен верить его анализу), то перемещение может не помочь, потому что вы не сможете фактически переименовать файл, открытый другим процессом. (Но тогда вы могли бы, я не знаю этого.) Если это действительно так, единственный способ, который я могу придумать, - «продолжать пытаться». Вам придется подождать несколько миллисекунд и повторить попытку. Храните тайм-аут, чтобы отказаться, когда это не поможет.

15
ответ дан sbi 21 August 2018 в 03:15
поделиться
  • 1
    Прохладная идея. Я не уверен, что это сработает для нашего реального сценария (что намного сложнее моего вопроса), но это может быть! :) – Mordachai 21 September 2010 в 21:48
  • 2
    @Mordachai: Возможно, вы захотите прочитать мое второе редактирование. Если Ханс прав, это может не помочь. Но вы всегда можете попробовать его в своей тестовой программе, чтобы увидеть, действительно ли сложно усложнять ваше реальное приложение. – sbi 21 September 2010 в 21:52
  • 3
    +1. вероятно, не имеет значения, прав ли Ганс. Вы можете переименовать открытые файлы. Это не проблема, потому что файловые дескрипторы в основном не зависят от имен файлов. Имя имеет значение только в момент создания дескриптора файла из имени файла. Гипотетический процесс с дескриптором открытого файла не будет затронут. – MSalters 22 September 2010 в 11:57
  • 4
    Кажется, это работает! В основном, я создаю временный файл (фактически создавая его с помощью GetTempFileName), а затем используя MoveFileEx, чтобы перезаписать уникальный файл temp с реальным, а затем выпустить DeleteFile в файле temp filename. До сих пор я не могу понять, что не так. Я ожидаю, что у вас есть производительность - не все так быстро, как все эти дополнительные накладные расходы, но чтобы изолировать наши scipters от тонкостей многозадачной файловой системы, это, вероятно, стоит того. – Mordachai 22 September 2010 в 16:01
  • 5
    @Mordachai: GetTempFileName() имеет для создания файла, иначе файл с одинаковым именем может быть создан кем-то еще между временем, когда вы получите уникальное имя файла и когда вы действительно создаете файл. В любом случае, рад, что вы его работали. – sbi 22 September 2010 в 17:17

Согласно [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

1
ответ дан Ajay 21 August 2018 в 03:15
поделиться
  • 1
    Это не верно. NtDeleteFile только делает настройку удаления более эффективной, пропуская двухступенчатую последовательность NtOpenFile, NtSetInformationFile и не требуя, чтобы менеджер ввода-вывода выделил реальный объект File. Конечно, ему все же приходится выделять IRP для запроса заданной информации и вызывать драйвер файловой системы, и, конечно, файл все равно не будет отсоединен до тех пор, пока последняя ссылка на файл не будет закрыта / очищена. – eryksun 11 April 2018 в 10:18

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

5
ответ дан Arkadiy 21 August 2018 в 03:15
поделиться
  • Есть ли способ обнаружить, что файл ожидает удаления?

Используйте функцию GetFileInformationByHandleEx с структурой FILE_STANDARD_INFO .

Но функция не может решить вашу проблему. @ sbi.

4
ответ дан Benjamin 21 August 2018 в 03:15
поделиться
  • 1
    Эмм, я не думаю, что это возможно [в нашей ситуации]. Совершенно откровенно, невозможно получить дескриптор файла, ожидающего удаления. Таким образом, к моменту выполнения CreateFile () файл находится в ожидании удаления, но его невозможно получить для проверки. :( – Mordachai 23 September 2010 в 15:20
  • 2
    Onces файл закроется как удаление, вы не сможете открыть файл еще раз. Это возможно только тогда, когда вы получили еще один дескриптор перед удалением файла. – Benjamin 23 September 2010 в 15:26
  • 3
    Правильно - поэтому любое полезное решение должно отвечать на вопрос «почему запрещен доступ». когда я вызываю CreateFile ()? Если есть способ спросить ОС, «находится файл, ожидающий удаления», в этот момент времени это было бы полезно. Или если был способ получить CreateFile (), чтобы быть более доступным с деталями вместо пустой & quot; denied & quot; то это было бы более полезно. – Mordachai 23 September 2010 в 17:09
  • 4
    В конечном счете, если кто-то не может запретить мне, почему MS не может сообщить более подробную информацию или скрыть эти махинации под обложками ОС, я должен сделать вывод, что это очень глупый, плохо продуманный механизм со стороны Microsoft , Я не против того, чтобы быть разочарованным. Если есть поистине веская причина, я все уши. Но пока это похоже на слияние неадекватно продуманных проектных решений на NTFS & amp; Команды команды Win32API. – Mordachai 23 September 2010 в 17:11
  • 5
    В режиме ядра NtCreateFile возвращает STATUS_DELETE_PENDING. Возможно, вы хотели. Но диспетчер ввода-вывода переводит ошибку в ERROR_ACCESS_DENIED перед возвратом CreateFile. support.microsoft.com/kb/113996 Я не знаю, почему они не передают его ERROR_DELETE_PENDING. Вы можете увидеть ERROR_DELETE_PENDING, когда вы открываете файл и удаляете и удаляете его еще раз, прежде чем закрыть дескриптор, который вы открыли. – Benjamin 7 December 2010 в 11:10

Возможно, я опаздываю на вечеринку, но в Vista / Win7 есть DeleteFileTransacted, который удаляет файл с помощью транзакций, которые гарантируют их удаление (очищает буферы файлов и т. д.). Для совместимости с XP это еще не вариант.

Еще одна идея, как это можно сделать, - это OpenFile с флагом OF_CREATE, который устанавливает длину до нуля, если файл существует, или создает его, если он этого не делает, а затем вызывает FlushFileBuffers в дескрипторе файла, чтобы дождаться завершения этой операции (создания нулевой длины файла). По завершении файл имеет размер 0, а затем просто вызывает DeleteFile.

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

1
ответ дан Coder12345 21 August 2018 в 03:15
поделиться
  • 1
    DeleteFileTransacted фактически разделяет поведение DeleteFile, что файл будет удален при закрытии последнего дескриптора. Цитата: & quot; Функция DeleteFileTransacted отмечает файл для удаления при закрытии. & Quot; из msdn.microsoft.com/en-us/library/windows/desktop/… – Christian K. 26 November 2015 в 15:25

Возможно, это не ваша конкретная проблема, но ее возможное, поэтому я предлагаю вам выйти из 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 теперь может открыть файл.

Конечно, предлагаемое решение ждать и повторять попытку, работает просто отлично.

4
ответ дан Craig 21 August 2018 в 03:15
поделиться
  • 1
    Да, это та же картина. В моем случае это был NOD32 Antivirus, но в целом проблема будет (потенциально) существовать на всех машинах Windows (и, возможно, в других операционных системах, в зависимости от того, как они обрабатывают свою файловую систему). Это не обязательно дефект дизайна в ОС (хотя почему они не сделали того, что я сделал [выпустить запись dir сразу после удаления, даже если ручки все еще открыты на ней] я не знаю). UPSHOT: любое программное обеспечение должно всегда записываться в & quot; wait & amp; повторите попытку & quot; или как указано "ответ" переименуйте, затем удалите. – Mordachai 7 December 2010 в 15:24
  • 2
    Кстати, это была бы отличная тема для Раймонда Чена. Жаль, что я не могу попасть в его очередь :( – Mordachai 7 December 2010 в 15:43

В Windows есть другие процессы, которые хотят часть этого файла. Индекс поиска является очевидным кандидатом. Или вирусный сканер. Они откроют файл для полного доступа, в том числе FILE_SHARE_DELETE, так что другие процессы не будут сильно зависеть от их открытия файла.

Это обычно хорошо работает, если вы не создаете / не записываете / не удаляете высокий уровень. Удаление будет успешным, но файл не сможет исчезнуть из файловой системы, пока последний дескриптор не будет закрыт. Ручка удерживается, скажем, поисковым индексом. Любая программа, которая пытается открыть этот файл ожидающего удаления, будет удалена с ошибкой 5.

В противном случае это общая проблема в многозадачной операционной системе, вы не можете знать, какой другой процесс может понадобиться для работы с вашими файлами , Ваша модель использования кажется необычной, сначала проверьте это. Обходным путем было бы уловить ошибку, спать и повторить попытку. Или перемещение файла в корзину с помощью SHFileOperation ().

20
ответ дан Hans Passant 21 August 2018 в 03:15
поделиться
  • 1
    Да, возможно, было бы разумно избегать этой картины! lol - к сожалению, я в роли сродни языковому разработчику, у которого есть программисты, которые используют указанный язык. Я могу сказать им, что некоторые шаблоны лучше избегать, но в конце концов они пишут свое программное обеспечение (скрипты), и я должен приложить все усилия, чтобы справиться с их ограниченной способностью обратить внимание на «лучшие практики». – Mordachai 21 September 2010 в 21:52
  • 2
    Ну, пытаясь скрыть поведение операционной системы real от этих скриптовых программистов, было бы серьезной ошибкой. Улучшите свой api, дайте возможность тем смиренным душам справиться с проблемой самостоятельно. Код ошибки, исключение, что угодно. Избегайте отношения Бога, вы просто создадите то, что все думают, сосут. Потому что у них есть эта проблема с их скриптом, который не работает без диагностики, и Бог не отвечает на их электронную почту. – Hans Passant 21 September 2010 в 22:05
  • 3
    На уровне C / C ++ / Java / любого другого основного языка программирования, я думаю, вы правы. И моя кишка полностью согласна с вами. Однако на уровне "упрощенного языка сценариев" - мы, как правило, живем по мантре ", если это разумно для сценариста, то двигатель должен сделать это." И цикл, который включает в себя подкомпонент, который генерирует данный файл, другой - процессы & amp; затем удаляет файл, а затем цикл этих двух блоков для некоторого большего усиления, возможно, разумный . Поэтому в этом случае мы сможем скрыть эту сложность от сценариста. – Mordachai 22 September 2010 в 14:53
  • 4
    Справедливости ради, это проблема, характерная для Windows, а не общая проблема os. Другие операционные системы легко справляются с этим, разрешив их эквивалент DeleteFile удалить имя без удаления файла, поэтому индексы не запрещают удалять файлы. Примерами такого поведения являются системы UNIX. Проблема существует, потому что Win32 (не NTFS) требует имя для каждого открытого файла. – Marc Lehmann 1 May 2013 в 04:38
  • 5
    Будут ли такие службы (например, поисковый индексатор) также пытаться читать временные файлы? – foresightyj 28 August 2015 в 02:25

Поскольку вы создаете новый файл, обрабатываете его, а затем удаляете его, это звучит так, как будто вы care не знаете, что такое имя файла. Если это действительно так, вам следует всегда подумать о создании временного файла . Таким образом, каждый раз через этот процесс вам не нужно care , чтобы файл еще не удалился.

3
ответ дан Jacob 21 August 2018 в 03:15
поделиться
  • 1
    -1 его вопрос указывает, что он не контролирует содержание сценариев, вызывающих это – Elemental 21 September 2010 в 22:27
  • 2
    @ Элементаль, точно. Он сказал контент для скриптов, а не location для скриптов, поэтому downvote недействителен. – Jacob 21 September 2010 в 22:32
  • 3
    @Jocab - к сожалению, сами скрипты содержат команды, включая команду delete, которая напрямую использует имя файла (буквально), и он не может изменять сценарии для использования имен файлов temp. – Elemental 22 September 2010 в 07:53
  • 4
    Это хорошая идея, Джейкоб, но наши сценаристы контролируют имя файла. И хотя этот конкретный сценарий возник, в общем, он этого не делает. На уровне языка (интерпретатор сценариев) невозможно воспринимать характер файла и применять к нему какие-либо определенные правила (это только имя выходного файла в одном контексте, имя входного файла в другом и цель команды удаления в еще одном, все не имеющие отношения к тому, что знает интерпретатор). – Mordachai 22 September 2010 в 14:44
  • 5
    Сценарий-интерпретатор может создавать уникально названные файлы в файловой системе и поддерживать сопоставление имен, используемых в скрипте, с именами фактической файловой системы. По завершении сценария интерпретатор может переименовать оставшиеся файлы в имена, требуемые сценарием, чтобы создать соответствующие побочные эффекты. – Adrian McCarthy 13 February 2015 в 17:55

Я думаю, что это просто плохой дизайн в файловой системе. Я видел ту же проблему, когда работал с коммуникационными портами, открывая / закрывая их.

К сожалению, я думаю, что самым простым решением было бы просто повторить попытку создания файла несколько раз, если вы получите INVALID_HANDLE_VALUE. GetLastError() может также дать вам лучший способ обнаружения этого конкретного INVALID_HANDLE_VALUE.

Я предпочел бы перекрытие ввода-вывода, но там CloseHandle() и DeleteFile() не обрабатывают перекрывающиеся операции: ([/ д2]

-2
ответ дан Max Kielland 21 August 2018 в 03:15
поделиться

У меня на самом деле была такая же проблема при использовании LoadLibrary ( path ). Я не смог удалить файл в пути .

Решение заключалось в том, чтобы «закрыть дескриптор» или использовать метод FreeLibrary ( path ).

ПРИМЕЧАНИЕ. Пожалуйста, прочитайте «Замечания» на MSDN относительно FreeLibrary ().

2
ответ дан OhadM 21 August 2018 в 03:15
поделиться

Если CreateFile возвращает INVALID_HANDLE_VALUE, тогда вы должны определить, что GetLastError возвращает в вашей конкретной ситуации (ожидающее удаления), и возвратить его обратно в CreateFile только на основе этого кода ошибки.

Изменить

Флаг FILE_FLAG_DELETE_ON_CLOSE вас купит?

1
ответ дан Pineapple 21 August 2018 в 03:15
поделиться
  • 1
    Я думаю, что ответы Windows & quot; Access Denied & quot; - это то, что возвращает GetLastError(). – sbi 21 September 2010 в 21:41
  • 2
    GetLastError () всегда "(5) Access Denied & quot; - что является довольно хромым, ограниченным ответом от ОС. Если это было "(91929) Ожидание удаления" тогда это было бы БОЛЬШОЙ! :) – Mordachai 21 September 2010 в 21:46
  • 3
    Спасибо за идеи, Ананас. К сожалению, механизм сценариев не знает, когда скрипт собирается удалить целевой файл (если он когда-либо), поэтому он не может пометить файл для удаления до того, как скрипт попросит об этом. И как только это произойдет, мы пощадим ОС для завершения операции. Если скрипт пытается выполнить еще одну команду, которая снова генерирует этот файл, а предыдущий не завершил, они получат эту ошибку. На самом деле это не под моим контролем то, что делает сценарист (и на первый взгляд, этот сценарий является разумным) – Mordachai 22 September 2010 в 14:48
Другие вопросы по тегам:

Похожие вопросы: