Мне нужно знать, что перед любой попыткой сделать что-либо с таким файлом.
Как проверить в командной строке, если данный файл или каталог заблокирован (используется любым процессом)?
Ответ 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