Jan Stanstrup
Jan Stanstrup

Reputation: 1232

Check if file is locked inside a batch file for loop

I have a script that runs through some files and copies them to another location. But the script needs to wait until the file is no longer being written to. I tried all the solutions here:

But the problem is that they don't work when wrapped in a loop. It always says the file is locked. If the script it cancelled and re-run it correctly finds the file unlocked. Am I doing something wrong or is there a trick to make this work?

For locking a test file, checkfile.txt, I do:

(
  >&2 pause
) >> checkfile.txt

Then the example script to check the file is this:

@echo off


for  %%i in (*.txt) do (

:loop
ping localhost -n 5 > nul
echo "check if locked"
powershell -Command "$FileStream = [System.IO.File]::Open('%%i', 'Open', 'Write'); $FileStream.Close(); $FileStream.Dispose()" >NUL 2>NUL || (goto :loop)

echo "NOT locked anymore"
)

Upvotes: 0

Views: 1047

Answers (2)

ebloch
ebloch

Reputation: 13

the following will have batch wait for a file to complete being written to:

:_WriteDelay TIMEOUT /T 60 > NUL

( (CALL ) >> < full path to file>) 2>NUL || GOTO _WriteDelay

Upvotes: 0

user7818749
user7818749

Reputation:

You cannot goto in a loop as it will simply break the for loop entirely. Additionally, the exit code or errorlevel is set for the last successful command. In this case being the powershell dispose command. Simply do the loop outside of the code block:

@echo off & setlocal

for %%i in (*.txt) do call :loop %%~i
goto :EOF

:loop
powershell -Command "[System.IO.File]::Open('%1', 'Open', 'Write')">nul 2>&1 && echo %1 not locked || (
    echo %1 Locked
    ("%systemroot%\system32\timeout.exe" /t 3)>nul
    goto :loop
)

Note, the conditional operators (and &&) and (or ||) helps to evaluate the exit code without needing to do if and else statements.

Edit:

@echo off

for %%i in (*.txt) do (
    setlocal enabledelayedexpansion

    powershell -Command "[System.IO.File]::Open('%%~i', 'Open', 'Write')">nul 2>&1 && echo %%~i not locked || (
        echo %%~i Locked
        ("%systemroot%\system32\timeout.exe" /t 3)>nul
    endlocal
 )
)

Upvotes: 1

Related Questions