Подтвердить что ты не робот

Как проверить в командной строке, если данный файл или каталог заблокирован (используется любым процессом)?

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

4b9b3361

Ответ 1

Не знаете о заблокированных каталогах (есть ли у Windows это?)

Но определение того, записывается ли файл другим процессом, не сложно.

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

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

(
  >&2 pause
) >> test.txt

Когда я запускаю второй script из одного окна, а затем запускаю первый script из второго окна, я получаю свое "заблокированное" сообщение. Как только я нажимаю <Enter> в 1-ом окне, я получаю сообщение "разблокирован", если я запустил первый script.

Объяснение

Всякий раз, когда вывод команды перенаправляется в файл, файл, конечно, должен быть открыт для доступа на запись. Сценарий Windows CMD попытается открыть файл, даже если команда не производит никакого вывода.

Оператор перенаправления >> открывает файл в режиме добавления.

Итак, >>test.txt echo off попытается открыть файл, он ничего не записывает в файл (предполагая, что эхо уже выключено), а затем закрывает файл. Файл не изменяется каким-либо образом.

Большинство процессов блокирует файл, когда они открывают файл для доступа к записи. (Существуют системные вызовы ОС, которые позволяют открывать файл для записи в режиме общего доступа, но это не значение по умолчанию). Так что если в другом процессе уже есть "test.txt", заблокированный для записи, то перенаправление не будет выполнено со следующим сообщением об ошибке, отправленным в stderr - "Процесс не может получить доступ к файлу, потому что он используется другим процессом". Также при сбое перенаправления генерируется код ошибки. Если команда и перенаправление успешны, возвращается код успеха.

Просто добавление 2>nul в команду не будет препятствовать сообщению об ошибке, поскольку оно перенаправляет вывод ошибки для команды, а не перенаправление. Вот почему я заключу команду в круглые скобки и затем перенаправляю вывод ошибки в nul за пределами parens.

Таким образом, сообщение об ошибке эффективно скрыто, но код ошибки по-прежнему распространяется за пределами parens. Стандартные операторы Windows && и || используются для определения того, была ли команда внутри паренов успешной или неудачной. Предположительно echo off никогда не будет терпеть неудачу, поэтому единственной возможной причиной отказа будет перенаправление переназначения. Скорее всего, это не удается из-за проблемы с блокировкой, хотя технически могут быть другие причины отказа.

Это любопытная "функция", при которой Windows не устанавливает динамическую переменную% ERRORLEVEL% в ошибку при сбое перенаправления, если не используется оператор ||. (См. Перенаправление файлов в Windows и% errorlevel%). Поэтому оператор || должен прочитать возвращаемый код ошибки на некотором низком уровне, а не через переменную% ERRORLEVEL%.

Использование этих методов для обнаружения отказа перенаправления может быть очень полезным в пакетном контексте. Его можно использовать для установки блокировок, которые позволяют сериализовать несколько событий в параллельных процессах. Например, он может позволить нескольким процессам безопасно записывать в один и тот же файл журнала в "то же самое время". Как вы используете общие файлы журналов в Windows?


ИЗМЕНИТЬ

Относительно заблокированных папок. Я не уверен, как Windows это реализует, возможно, с блокировкой. Но если в процессе есть активный каталог с участием папки, папка не может быть переименована. Это легко обнаружить с помощью

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

ИЗМЕНИТЬ

С тех пор я узнал, что (call ) (с пробелом) - очень быстрая команда без побочных эффектов, которая, как гарантируется, будет успешной с установкой ERRORLEVEL на 0. И (call) (без пробела) - это быстрая команда без стороны эффекты, которые гарантированно потерпят неудачу с ERRORLEVEL 1.

Итак, теперь я использую следующее, чтобы проверить, заблокирован ли файл:

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

Ответ 2

В дополнение к отличный ответ от dbenham, следующая форма, наконец, поможет мне понять используемую технику:

( type nul >> file.txt ) 2>nul || echo File is locked!
Команда

type nul дает пустой вывод и не влияет на текущую настройку эха, такую ​​как echo off команда в оригинале.

Если вы хотите использовать условие if–then–else, помните правильный порядок - утверждение успеха (&&) идет первым, а альтернативный оператор (||) занимает второе место:

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

Ответ 3

При загрузке и установке средств набора ресурсов Windows Server 2003 есть утилита под названием oh.exe, в которой будут перечислены файлы открытых файлов для данного файла:

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

После его установки перезагрузите компьютер, и вы сможете использовать эту утилиту. Вы можете увидеть все параметры в центре справки и поддержки, а также ввести oh /? в командной строке.

(Информация от: http://windowsxp.mvps.org/processlock.htm)

Ответ 4

Примечание. Запись сообщения о статусе файла была менее полезна, чем командная команда, устанавливающая код возврата. Например, верните код 1, если файл заблокирован.

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

Ответ 5

Просто я хочу поделиться с вами примером моего script на основе трюка @dbenham

Описание этого script: Check_Locked_Files.bat: Этот script может сканировать и проверять заблокированные файлы на набор папок, которые можно изменить в script; например, я выбрал тот набор сканируемых папок:

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%" 

Результат вывода в формате HTML для большей удобочитаемости.

Если файл заблокирован, мы показываем его красным цветом, иначе мы показываем его зеленым цветом.

И весь 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%"
::**************************************************************

Ответ 6

Кстати, решение dbenham также представляется эффективным способом выяснить, работает ли процесс. Это было лучшее решение, которое я нашел для следующего приложения:

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

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

comparejobs.exe

Ответ 7

:: 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