2012-05-09 10 views
14

Ho bisogno di sapere che prima di ogni tentativo di fare qualsiasi cosa con tale file.Come controllare la riga di comando se un determinato file o directory è bloccato (utilizzato da qualsiasi processo)?

+1

Ci dispiace ma non è possibile farlo. Dalla riga di comando non c'è modo di sapere se un file è bloccato da un processo (devi provare a fare qualcosa con esso e "catturare" l'errore). –

+0

Penso che PowerShell potrebbe determinare questo. (Sto appena iniziando a leggere Powershell in azione, sono molto impressionato). In Unix, i file bloccati non sono un problema;^/) Buona fortuna a tutti. – shellter

+3

@Adriano - non è vero. Vedere la mia risposta http://stackoverflow.com/a/10520609/1012053 – dbenham

risposta

55

Non sei sicuro di directory bloccate

Ma rilevare se un file è in fase di scrittura da un altro processo non è difficile.

@echo off 
2>nul (
    >>test.txt echo off 
) && (echo file is not locked) || (echo file is locked) 

Io uso il seguente script di test da un'altra finestra per posizionare un blocco sul file.

(
    >&2 pause 
) >> test.txt 

Quando eseguo il 2 ° script da una finestra e quindi eseguire il primo script da una seconda finestra, ottengo il mio messaggio "bloccato". Dopo aver premuto <Enter> nella prima finestra, ottengo il messaggio "sbloccato" se rieseguo il primo script.

Spiegazione

Ogni volta che l'output di un comando viene reindirizzato a un file, il file ovviamente deve essere aperta per l'accesso in scrittura. La sessione CMD di Windows tenterà di aprire il file, anche se il comando non produce alcun output.

L'operatore di reindirizzamento >> apre il file in modalità di aggiunta.

Quindi >>test.txt echo off tenterà di aprire il file, non scrive nulla sul file (presupponendo che echo sia già disattivato) e quindi chiude il file. Il file non è stato modificato in alcun modo.

La maggior parte dei processi blocca un file ogni volta che apre un file per l'accesso in scrittura. (Esistono chiamate di sistema del sistema operativo che consentono l'apertura di un file per la scrittura in una modalità condivisa, ma non è quella predefinita). Quindi se un altro processo ha già "test.txt" bloccato per la scrittura, il reindirizzamento fallirà con il seguente messaggio di errore inviato a stderr - "Il processo non può accedere al file perché è utilizzato da un altro processo.". Inoltre verrà generato un codice di errore in caso di errore di reindirizzamento. Se il comando e il reindirizzamento hanno esito positivo, viene restituito un codice di successo.

Aggiungere semplicemente 2>nul al comando non impedirà il messaggio di errore perché reindirizza l'output dell'errore per il comando, non il reindirizzamento. Ecco perché accludo il comando tra parentesi e poi reindirizzo l'output dell'errore a nul al di fuori del paren.

Quindi il messaggio di errore è effettivamente nascosto, ma il codice di errore è ancora propagato al di fuori del paren. Gli operatori standard di Windows && e || vengono utilizzati per rilevare se il comando all'interno del paren ha avuto esito positivo o negativo.Presumibilmente echo off non fallirà mai, quindi l'unico motivo possibile per l'errore sarebbe il reindirizzamento non riuscito. Molto probabilmente fallisce a causa di un problema di blocco, anche se tecnicamente potrebbero esserci altri motivi di fallimento.

È una curiosa "funzionalità" che Windows non imposta la variabile dinamica% ERRORLEVEL% su un errore in caso di errore di reindirizzamento a meno che non venga utilizzato l'operatore ||. (Vedi File redirection in Windows and %errorlevel%). Pertanto, l'operatore || deve leggere il codice di errore restituito a un livello basso, non tramite la variabile% ERRORLEVEL%.

L'utilizzo di queste tecniche per rilevare errori di reindirizzamento può essere molto utile in un contesto batch. Può essere utilizzato per stabilire blocchi che consentono la serializzazione di più eventi in processi paralleli. Ad esempio, può consentire a più processi di scrivere in modo sicuro nello stesso file di registro nello stesso "tempo". How do you have shared log files under Windows?


EDIT

Per quanto riguarda le cartelle bloccate. Non sono sicuro di come Windows implementa questo, forse con un lucchetto. Ma se un processo ha una directory attiva che coinvolge la cartella, la cartella non può essere rinominata. Che può essere facilmente individuati utilizzando

2>nul ren folderName folderName && echo Folder is NOT locked || echo folder is LOCKED 

EDIT

Da allora ho imparato che (call)(con uno spazio) è un comando molto veloce senza effetti collaterali che è garantito per avere successo con il set ERRORLEVEL a 0. E (senza spazio) è un comando rapido senza effetti collaterali che è garantito fallire con ERRORLEVEL 1.

Così ho ora utilizzare la seguente per verificare se un file è bloccato:

2>nul (
    >>test.txt (call) 
) && (echo file is not locked) || (echo file is locked) 
+0

+1 per la pura sintassi cmd (sto ancora cercando di capire come e perché funziona !!!) –

+2

@Adriano - Spiegazione aggiunta :-) – dbenham

+2

Fantastico, mi dispiace non posso andare più di una volta !!! –

7

Se scaricare e installare gli strumenti del resource kit di Windows Server 2003 esiste un'utility chiamata oh.exe che elencherà file aperto maniglie per un dato file:

http://www.microsoft.com/en-us/download/details.aspx?id=17657

Una volta installato, riavviare la macchina e sarai in grado di utilizzare l'utilità. È possibile visualizzare tutte le opzioni nel Centro assistenza e supporto, nonché digitando oh /? nel prompt dei comandi.

(Info da: http://windowsxp.mvps.org/processlock.htm) (? Funziona Windows ha che)

9

Oltre a great answer dal dbenham, il seguente modulo, infine, aiutarmi a capire la tecnica utilizzata:

(type nul >> file.txt) 2>nul || echo File is locked! 

type nul comando dà un output vuoto e non influenza l'impostazione di eco corrente come il comando echo off in originale.

Se si desidera utilizzare if–then–else condizioni ricordate di ordine corretto - dichiarazione successo (&&) sta prima e la dichiarazione alternativo (||) sta andando secondo:

command && (echo Command is successful) || (echo Command has failed) 
+2

Attenzione con 'if && then || formato else', ricorda che il blocco 'else' verrà eseguito anche se il blocco' then' fallisce. – remram

0

Per inciso, la soluzione di dbenham sembra anche essere un modo efficace per scoprire se un processo è in esecuzione. E 'stata la soluzione migliore che ho trovato per la seguente applicazione:

start /b "job1.exe >> job1.out" 
start /b /wait "job2.exe >> job2.out" 

::wait for job1 to finish using dbenham's code to check if job1.out is in use 

comparejobs.exe 
1

nota, la scrittura di un messaggio che indica lo stato del file è stato meno utile di un comando batch che impostare un codice di ritorno. Ad esempio, restituire il codice 1 se il file è bloccato.

@echo off 
2>nul (
    >>test.tmp echo off 
) && (EXIT /B 0) || (EXIT /B 1) 
1

Solo che voglio condividere con voi un esempio del mio script sulla base di trucco di @ dbenham

descrizione di questo script: Check_Locked_Files.bat: Questo script può eseguire la scansione e verificare la presenza bloccato file su una serie di cartelle che possono essere modificate nello script; ad esempio, ho scelto il set di cartelle da scansionare:

Set Folders=^ 
^ "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup"^ 
^ "%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"^ 
^ "%ProgramFiles%\Internet Explorer"^ 
^ "%ProgramFiles%\Skype"^ 
^ "%ProgramFiles%\TeamViewer"^ 
^ "%WinDir%\system32\drivers"^ 
^ "%Temp%" 

Il risultato di output è in formato HTML per una maggiore leggibilità.

Se il file è bloccato, lo mostriamo in rosso altrimenti lo mostriamo in verde.

E l'intero script è: Check_Locked_Files.bat

@echo off 
Rem This source is inspired from here 
Rem hxxps://stackoverflow.com/questions/ 
Rem 10518151/how-to-check-in-command-line-if-a-given-file-or-directory-is-locked-used-by-any?answertab=active#tab-top 
Rem Thanks for dbenham for this nice trick ;) 
Mode con cols=90 lines=5 & color 9E 
Title Scan and Check for Locked Files by Hackoo 2017 
set "LogFile=%~dp0%~n0.html" 
(
    echo ^<html^> 
    echo ^<title^> Scan and Check for locked files by Hackoo 2017^</title^> 
    echo ^<body bgcolor^=#ffdfb7^> 
    echo ^<center^>^<b^>Log Started on %Date% @ %Time% by the user : "%username%" on the computer : "%ComputerName%"^</b^>^</center^> 
)> "%LogFile%" 
echo(
echo  -------------------------------------------------------------------------- 
echo   Please Wait a while ....... Scanning for locked files is in progress 
echo  -------------------------------------------------------------------------- 
Rem We Play radio just for fun and in order to let the user be patient until the scan ended 
Call :Play_DJ_Buzz_Radio 
Timeout /T 3 /nobreak>nul 
cls 
Set Folders=^ 
^ "%ProgramData%\Microsoft\Windows\Start Menu\Programs\Startup"^ 
^ "%UserProfile%\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup"^ 
^ "%ProgramFiles%\Internet Explorer"^ 
^ "%ProgramFiles%\Skype"^ 
^ "%ProgramFiles%\TeamViewer"^ 
^ "%WinDir%\system32\drivers"^ 
^ "%Temp%" 

@For %%a in (%Folders%) Do (
    (echo ^<hr^>^<font color^=DarkOrange^>^<B^>Folder : %%a^</B^>^</font^>^<hr^>) >> "%LogFile%" 
    @for /f "delims=" %%b in ('Dir /A-D /s /b "%%~a\*.*"') do (
     Call :Scanning "%%~nxb" 
     Call:Check_Locked_File "%%~b" "%LogFile%" 
    ) 
) 

(
    echo ^<hr^> 
    echo ^<center^>^<b^>Log ended on %Date% @ %Time% on the computer : "%ComputerName%"^</b^>^</center^> 
    echo ^</body^> 
    echo ^</html^> 
)>> "%LogFile%" 
Start "" "%LogFile%" & Call :Stop_Radio & exit 
::*********************************************************************************** 
:Check_Locked_File <File> <LogFile> 
(
    2>nul (
    >>%1 (call) 
    ) && (@echo ^<font color^=green^>file "%~1"^</font^>^<br^> 
    ) || ( 
     @echo ^<font color^=red^>file "%~1" is locked and is in use^</font^>^<br^> 
    ) 
)>>%2 2>nul 
exit /b 
::*********************************************************************************** 
:Scanning <file> 
cls 
echo(
echo  -------------------------------------------------------------------------- 
echo   Please Wait a while... Scanning for %1 
echo  -------------------------------------------------------------------------- 
exit /b 
::*********************************************************************************** 
:Play_DJ_Buzz_Radio 
Taskkill /IM "wscript.exe" /F >nul 2>&1 
Set "vbsfile=%temp%\DJBuzzRadio.vbs" 
Set "URL=http://www.chocradios.ch/djbuzzradio_windows.mp3.asx" 
Call:Play "%URL%" "%vbsfile%" 
Start "" "%vbsfile%" 
Exit /b 
::************************************************************** 
:Play 
(
echo Play "%~1" 
echo Sub Play(URL^) 
echo Dim Sound 
echo Set Sound = CreateObject("WMPlayer.OCX"^) 
echo Sound.URL = URL 
echo Sound.settings.volume = 100 
echo Sound.Controls.play 
echo do while Sound.currentmedia.duration = 0 
echo  wscript.sleep 100 
echo loop 
echo wscript.sleep (int(Sound.currentmedia.duration^)+1^)*1000 
echo End Sub 
)>%~2 
exit /b 
::************************************************************** 
:Stop_Radio 
Taskkill /IM "wscript.exe" /F >nul 2>&1 
If Exist "%vbsfile%" Del "%vbsfile%" 
::************************************************************** 
0
:: Create the file Running.tmp 

ECHO %DATE% > Running.tmp 
ECHO %TIME% >> Running.tmp 

:: block it and do the work 

(
    >&2 CALL :Work 30 
) >> Running.tmp 

:: when the work is finished, delete the file 
DEL Running.tmp 
GOTO EOF 

:: put here the work to be done by the batch file 

:Work 
ping 127.0.0.1 -n 2 -w 1000 > NUL 
ping 127.0.0.1 -n %1 -w 1000 > NUL 

:: when the process finishes, the execution go back 
:: to the line after the CALL 
Problemi correlati