Como fechar todos os identificadores de arquivo em uma determinada pasta programaticamente?

18

Fiquei me perguntando se existe uma ferramenta de linha de comando que permita fechar todos os identificadores de arquivo que estão abertos em uma pasta específica.

Eu tentei ProcessExplorer , Unlocker e ferramentas similares, mas elas oferecem uma interface GUI e não são úteis em um ambiente de programação

Uma solução em Python, cmd ou PowerShell seria ideal.

Amelio Vazquez-Reina
fonte
Lembre-se de que o fechamento forçado de um identificador de arquivo pode causar uma falha no programa que o utiliza.
Harry Johnston
1
@HarryJohnston Pior, você pode acabar causando todos os tipos de corrupção de arquivos enquanto o programa estiver aberto: technet.microsoft.com/en-us/magazine/…
Bob

Respostas:

7

O Unlocker afirma que lhe dá esta capacidade:

  1. Basta clicar com o botão direito na pasta ou arquivo e selecionar Desbloquear

    Passo 1

  2. Se a pasta ou arquivo estiver bloqueado, aparecerá uma lista de armários na janela

    Passo 2

  3. Basta clicar Unlock Alle pronto!

Não tenho certeza se ele suporta o uso da linha de comando.

FileASSASSIN de Malwarebyte executa ações semelhantes, e faz uso de linha de comando apoio, para que você deve ser capaz de escrevê-lo muito facilmente.

Opções de FileAssassin

Ƭᴇcʜιᴇ007
fonte
Obrigado techie007, acho que perdi isso. Notei que o Unlocker às vezes perde meus arquivos (o ProcessExplorer não). Um segundo problema é se eu quero desbloquear ou liberar arquivos programaticamente (por exemplo, uma ferramenta de linha de comando ajudaria nessa direção).
Amelio Vazquez-Reina
@intrpc Pronto, adicionei outra sugestão (compatível com a linha de comando). :)
Ƭᴇcʜιᴇ007 13/09/11
1
Cuidado, o Unlocker vem com malware atualmente.
27517 Joshua Hanley
10

Obrigado por isso. Temos tido alguns problemas com identificadores de arquivos abertos, causando falhas nos check-ins do git em nossos trabalhos Jenkins baseados no Windows e isso ajudou a corrigir o problema com facilidade. Vou jogar fora o básico da técnica:

  1. Instale o Handle.exe no nó de compilação. Fiz o download aqui http://technet.microsoft.com/en-us/sysinternals/bb896655 , descompactei e soltei o Handle.exe em C: \ Windows \ System32 para garantir que ele estivesse disponível no% PATH% padrão

  2. Instale o plug-in Jenkins pré-scm-buildstep: https://wiki.jenkins-ci.org/display/JENKINS/pre-scm-buildstep . Isso nos permite definir operações antes que o plugin git comece a buscar arquivos potencialmente bloqueados.

  3. Implementou o seguinte comando em lote como uma etapa de construção pré-scm:

    @echo off
    echo Cleaning up open file handles from %NODE_NAME%:%WORKSPACE%...
    for /f "tokens=3,6,8 delims=: " %%i in ('Handle /accepteula %WORKSPACE% ^| grep workspace') do echo Releasing file lock on E:%%k & handle -c %%j -y -p %%i
    

Parece funcionar bem e definitivamente reduz falhas espúrias. Também observarei algumas dicas pelas quais trabalhei:

  • Handler.exe possui um EULA que deve ser aceito na primeira vez em que é executado. Se você estiver executando o agente Jenkins como um serviço no contexto do sistema local, isso é problemático porque você não pode efetuar login como esse usuário e aceitá-lo manualmente. Quando tentamos executá-lo a partir do trabalho de Jenkins, o processo simplesmente aguardou a entrada do usuário e levou alguns minutos para descobrir o porquê. Resolvi isso executando-o no trabalho Jenkins usando o sinalizador / accepteula e recomendo que qualquer pessoa que implemente isso como um processo automatizado faça o mesmo. Essa é uma configuração de registro em HKEY_CURRENT_USER \ Software \ Sysinternals \ Handle e você também pode defini-la e desabilitá-la através do regedit.exe se precisar manipulá-la para um usuário específico, mas a opção da linha de comando parecia mais fácil.

  • O plugin da etapa Jenkins Batch executa o código do lote como se estivesse em um script, e não como uma diretiva de linha de comando. Observe as fugas (por exemplo, %% i, ^ |).

Obrigado!

Thomas Boyles
fonte
Lutando para obter a sintaxe disso, alguém pode fornecer mais detalhes sobre o que é %% i, j etc?
C4sh
Esta ajuda poder entender a sintaxe do comando batch: robvanderwoude.com/ntfortokens.php
c4sh
Como vocês resolveram o fato de o handle.exe precisar ser executado como administrador, enquanto o executamos a partir de um usuário do Jenkins que não é administrador?
C4sh
8

Usamos o seguinte snippet para fechar a manipulação de arquivos dos usuários para o nosso servidor. Você pode modificá-lo para seu uso.

rem close all network files that are locked
for /f "skip=4 tokens=1" %%a in ('net files') do net files %%a /close
Brendan
fonte
Obrigado @Brendan. Acho que seu código não foi formatado corretamente. Sua resposta parece interessante; portanto, se você não se importa de editá-la, sugiro que você selecione suas linhas de código e clique no botão com as duas pulseiras encaracoladas. Isso transformará seu snippet em código legível.
Amelio Vazquez-Reina
5

Eu crio esse pequeno arquivo em lotes para liberar automaticamente todos os bloqueios para o arquivo xml pelo meu eclipse

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle -p eclipse e:\git\ ^| grep .xml') do echo Releasing %%k & handle -c %%j -y -p %%i

Você precisa baixar o utilitário de manipulação do site da Microsoft e o utilitário grep do GnuWin32

Se você não precisar filtrar por tipo de arquivo, poderá pular a parte grep como esta:

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle -p eclipse e:\git\') do echo Releasing %%k & handle -c %%j -y -p %%i

Ou, se você não precisar filtrar bloqueios por um programa específico, basta remover o filtro de processo do eclipse:

@echo off
for /f "tokens=3,6,8 delims=: " %%i in ('handle e:\git\') do echo Releasing %%k & handle -c %%j -y -p %%i

Lembre-se de substituir e:\git\pelo caminho da pasta.

coolersport
fonte
4

Se você estiver usando o PSTools , isso forçará o fechamento de todos os arquivos abertos recursivamente:

psfile \\serverName c:\path\toDatabase\ -c

Observe que c:\path\toDatabase\a unidade C: está ligada \\serverName, não a máquina local. Isso não estava claro para mim no começo, então pensei em apontar isso.

Essa é uma abordagem de força bruta que quase garante a perda de dados, portanto, use-a com cautela.

Temos um banco de dados do Access mal montado que literalmente leva a empresa a ficar de joelhos regularmente (tive que corrigi-lo três vezes ontem).

O cara que normalmente lida com isso fica de férias por algumas semanas e suas instruções usam uma abordagem baseada na interface do usuário (Iniciar> Computador> Gerenciar> Gerenciamento do computador (local)> Conectar-se a outro computador> Ferramentas do sistema> Pastas compartilhadas> Abrir arquivos> Fechar Abrir arquivos). MUITOS cliques quando posso executar o comando acima e expulsar toda a empresa de todos os arquivos de banco de dados e iniciar o processo Compactar e reparar (para o qual também estou trabalhando em uma abordagem de script de força bruta).

O truque é ficar à frente das pessoas que imediatamente começam a se reconectar ao banco de dados assim que ele desativa. Eles estão tão acostumados a isso que não lhes ocorre registrar um bug, eles continuam martelando o banco de dados até voltarem. Eu continuo inicializando-os até compactar e reparar as três dúzias arquivos que compõem o banco de dados.

delliottg
fonte
4

Se você está falando sobre identificadores de arquivos abertos por meio de um compartilhamento SMB em um servidor de arquivos do Windows (Server 2012 ou mais recente), aqui está a resposta do PowerShell:

Get-SmbOpenFile | Where-Object { $_.Path -like "D:\Folder\*" } | Close-SmbOpenFile -Force

Em um servidor de arquivos Windows mais antigo, é openfiles.exe /disconnect.

Para um identificador de arquivo do sistema local, a melhor maneira que encontrei é usar o Sysinternals handle.exe

Joshua Hanley
fonte
3

Eu prefiro o http://lockhunter.com porque suporta GUI e interface de linha de comando e, em muitos casos, foi capaz de excluir arquivos que não puderam ser excluídos pelo Unlocker.

Vladimir Reshetnikov
fonte
2

O Unlocker também pode ser executado no modo silencioso.

Por exemplo, para desbloquear todos os arquivos na área de trabalho do Jenkins:

"C:\Program Files\Unlocker\unlocker.exe" "%WORKSPACE%" /S

Em seguida, você pode excluir com segurança os arquivos da área de trabalho:

del "%WORKSPACE%\*.*" /s /q
Noam Manos
fonte
0

Você pode usar o Powershell para fazer isso:

function KillProcessesWithHandles
{
    param([string]$path)

    $allProcesses = Get-Process

    # Start by closing all notepad processes. Someone may have left a logor config file open
    $allProcesses | Where-Object {$_.Name -eq "notepad"} | Stop-Process -Force -ErrorAction SilentlyContinue

    # Then close all processes running inside the folder we are trying to delete
    $allProcesses | Where-Object {$_.Path -like ($path + "*")} | Stop-Process -Force -ErrorAction SilentlyContinue

    # Finally close all processes with modules loaded from folder we are trying to delete
    foreach($lockedFile in Get-ChildItem -Path $path -Include * -Recurse) {
        foreach ($process in $allProcesses) {
            $process.Modules | Where-Object {$_.FileName -eq $lockedFile} | Stop-Process -Force -ErrorAction SilentlyContinue
        }
    }
}

Para obter mais detalhes, consulte Thomas Ardal aqui: https://thomasardal.com/deleting-contents-of-a-folder-containing-files-with-open-file-handles-using-powershell/

Abhi
fonte