检查目录中的文件是不是仍在使用 Windows 批处理脚本写入

Posted

技术标签:

【中文标题】检查目录中的文件是不是仍在使用 Windows 批处理脚本写入【英文标题】:Check if files in a directory are still being written using Windows Batch Script检查目录中的文件是否仍在使用 Windows 批处理脚本写入 【发布时间】:2010-03-29 23:07:35 【问题描述】:

这是我解析目录的批处理文件,以及特定类型的压缩文件

 REM Begin ------------------------
    tasklist /FI "IMAGENAME eq 7za.exe" /FO CSV > search.log
    FOR /F %%A IN (search.log) DO IF %%~zA EQU 0 GOTO end
    for /f "delims=" %%A in ('dir C:\Temp\*.ps /b') do (
"C:\Program Files\7-Zip\cmdline\7za.exe" a -tzip -mx9 "C:\temp\Zip\%%A.zip" "C:\temp\%%A"
Move "C:\temp\%%A" "C:\Temp\Archive"
)
    :end
    del search.log
    REM pause
    exit
    REM End ---------------------------

这段代码可以很好地满足我 90% 的需求。它将作为计划任务部署。

但是,在实时情况下,*.ps 文件相当大(最小为 1GB)。所以代码应该检查传入的文件是否已完全写入并且没有被正在编写它的应用程序锁定。

我在其他地方看到了另一个示例,建议采用以下方法

:TestFile
ren c:\file.txt c:\file.txt
if errorlevel 0 goto docopy
sleep 5
goto TestFile
:docopy

不过,这个例子适用于固定文件。如何在 for 循环中使用这么多标签和 GoTo 而不会导致无限循环?或者这段代码在 For 循环中使用是否安全?

感谢您的帮助。

【问题讨论】:

【参考方案1】:

我同意 GOTO 循环是有风险的——一个错误会导致它永远循环,这对于计划任务来说一点也不好。

对于这样的任务,我倾向于使用Resource Kit tool called Robocopy,部分原因是它速度很快,但也因为它很健壮。如果文件未准备好(/w:10),我通常将其设置为重试 3-5 次(选项 /r:3),暂停 10 秒(/w:10),然后让它记录任何错误,以便我查看它们(/log:...) .非常便利。这是the full list of options,它可以帮助您准确地选择您需要复制的内容。

我的第一反应可能有点草率。小重命名技巧可以集成到您的脚本中,并且可能会正常工作:

...
for /f "delims=" %%A in ('dir C:\Temp\*.ps /b') do (
:TestFile
ren C:\Temp\%%A.ps C:\Temp\%%A.ps
if errorlevel 0 goto Continue
sleep 5
goto TestFile
:Continue
"C:\Program Files\7-Zip\cmdline\7za.exe" a -tzip -mx9 "C:\temp\Zip\%%A.zip" "C:\temp\%%A"
move "C:\temp\%%A" "C:\Temp\Archive"
)
...

或者,如果您想使用 Robocopy,您可以先移动文件,然后再进行压缩。 (只要您将文件移动到同一个分区上——在你的例子中,它是从 C:\TEMP 到 C:\TEMP\Archived——没有延迟。)这样 Robocopy 将一直等到文件准备好,然后让你的脚本继续压缩。这是一个例子:

...
for /f "delims=" %%A in ('dir C:\Temp\*.ps /b') do (
robocopy C:\Temp C:\Temp\Archive\ %%A.ps /mov /r:100 /w:5 /log+:copylog.txt
"C:\Program Files\7-Zip\cmdline\7za.exe" a -tzip -mx9 "C:\temp\Archive\%%A.zip" "C:\temp\Archive\%%A.ps"
)
...

【讨论】:

即使重命名尝试失败,上面的 ren 命令也会返回 ErrorLevel 为 0。我们如何真正识别重命名失败? 我的测试表明,对于失败的重命名,ErrorLevel 设置为 1,就像复制、移动等失败一样。而且 robocopy 选项仍然可以工作。 :)【参考方案2】:

以下是我最终使用的批处理文件脚本。它非常适合要求。我希望它可以帮助与我有相同要求的人。

tasklist /FI "IMAGENAME eq 7za.exe" /FO CSV > search.log
FOR /F %%%A IN (search.log) DO IF %%%~zA EQU 0 GOTO end
for /f "delims=" %%A in ('dir C:\Temp\ZIP\*.txt /b') do (
     :TestFile 
    "C:\Program Files\7-Zip\cmdline\7za.exe" a -tzip -mx9 "C:\temp\Zip\ZipDone%%A.zip" "C:\temp\zip\%%A"
     Move "C:\temp\ZIP\%%A" "C:\Temp\ZIP\Archive"
     )
:end
del search.log
REM pause
Exit

【讨论】:

以上是关于检查目录中的文件是不是仍在使用 Windows 批处理脚本写入的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法检查子进程是不是仍在运行?

如何检查 PHP 中父文件夹中的文件夹或目录是不是可用?

C如何检查内存地址是不是仍在范围内[关闭]

检查字符串是不是是有效的 Windows 目录(文件夹)路径

检查路径上的对象是不是是跨平台的文件或目录?

检查用户是不是仍在 angularfire2 中通过身份验证