我想在命令行中将每个文件夹中存在的ZIP和RAR存档提取到相应的文件夹中。此外,我只想在解压缩过程中没有错误的情况下删除原始压缩文件。如果提取存档时出错,则应将存档文件名写入错误日志文件,并且提取过程应继续下一个存档文件。
我想在解压缩成功后将每个文件夹移至xsl:choose
文件夹。但是批处理文件不应移动不包含任何存档文件的文件夹。
之前:
Part
之后:
Part
下面的代码是从Mofi从问题的初始版本中得到的答案,并由我改编而成的。
done
答案 0 :(得分:0)
Rar.exe
仅支持 WinRAR 的程序文件文件夹中手册Rar.txt
顶部所述的RAR存档。 WinRAR.exe
支持创建RAR和ZIP存档以及提取多种存档类型。因此,WinRAR.exe
用于下面的批处理文件代码。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
set "ArchiveExtracted="
del /Q "%LogExtract%" "%LogError%" 2>nul
for /D %%I in ("%SourceFolder%\*") do (
if /I not "%%~nxI" == "done" (
for %%J in ("%%I\*.rar" "%%I\*.zip") do (
if exist "%%J" (
echo Extracting "%%J" ...
"%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%%J" "%%I\"
if errorlevel 1 (
set "ArchiveFile=%%J"
>>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
) else (
set "#%%~nxI=%%I"
set "ArchiveExtracted=1"
echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
if errorlevel 1 ( del /F "%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%%I\%%~n#.part*%%~xJ"
)
)
)
)
)
if defined ArchiveExtracted (
md "%SourceFolder%\done" 2>nul
if exist "%SourceFolder%\done\" (
for /F "tokens=2 delims==" %%I in ('set #') do move /Y "%%I" "%SourceFolder%\done\"
)
)
endlocal
定义父源文件夹并从以前的执行中删除可能已经存在的日志文件后,外部 FOR 会在指定的源文件夹中搜索未隐藏的子目录。
对于每个找到的子目录(名称为done
的子目录除外),内部 FOR 会在子目录中搜索未隐藏的* .rar和* .zip文件,并执行WinRAR.exe
将找到的每个存档文件提取到子目录中。
WinRAR 提取每个存档文件
WinRAR 自动提取多卷存档的所有卷。
WinRAR 的错误值为更大或等于 1
退出,如帮助页面 WinRAR 的帮助中所述< em> WinRAR退出代码列表。
如果未成功提取由 WinRAR 退出且值为ArchiveFile
的归档文件,归档文件名将分配给环境变量0
,并且接下来,输出一条错误消息行,将 WinRAR 的退出代码和文件名写入错误日志文件。错误日志文件的编码取决于Windows命令处理器在开始批处理文件处理时定义的字符编码和代码页。
环境变量ErrorLevel
和ArchiveFile
的两边都用两个百分号引用,因为Windows指令处理器在执行外部 FOR 之前已在解析整个命令块时已替换掉它们%%
到%
之间。在执行 ECHO 之前,命令 CALL 导致对 ECHO 命令行的第二次解析,从而导致将%Errorlevel%
替换为当前值此环境变量以及%ArchiveFile%
(按当前存档文件名)。
像echo Error %ErrorLevel% on extracting "%ArchiveFile%"
这样的 ECHO 行,没有命令 CALL ,将导致%ErrorLevel%
被环境变量ErrorLevel
的当前值代替外部 FOR 完全执行,这意味着用0
并将%ArchiveFile%
替换为空字符串,这当然无济于事。
将存档文件名分配给环境变量ArchiveFile
,并像ErrorLevel
一样引用,以正确处理文件名Archive%20!Important!.rar
。
在多卷归档文件上出现错误时,不会删除任何RAR归档文件部分,从而导致提取多卷归档文件的所有卷多次,并且将多卷归档文件的每个部分都写入错误日志中。文件。
在成功提取单个存档文件时删除存档文件,或者在成功提取多卷存档时删除多卷存档的所有部分。另外,使用#
加上环境变量名称和子目录的完整路径作为值来设置环境变量,以记住哪些子目录包含至少一个成功提取的存档以供以后移动。对于这种简单的方法,要求子目录名称中都不能包含等号。
以上代码无法在子目录中多个* .rar或* .zip文件中的FAT32或ExFAT驱动器上使用。在这种情况下,有必要在以%ComSpec% /C
为背景的单独命令过程中使用由 FOR 执行的命令 DIR ,并捕获输出存档文件名。然后,内部的 FOR 会运行一系列由于在FAT32和ExFAT驱动器上删除存档文件而导致在循环迭代期间未修改的存档文件名。
如果归档文件本身包含* .rar或* .zip文件,并且上面的批处理代码可能会偶然提取该文件,则也需要此备用批处理文件。
因此,第二个批处理代码比第一个更安全。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
set "ArchiveExtracted="
del /Q "%LogExtract%" "%LogError%" 2>nul
for /D %%I in ("%SourceFolder%\*") do (
if /I not "%%~nxI" == "done" (
for /F "eol=| delims=" %%J in ('dir "%%I\*.rar" "%%I\*.zip" /A-D-H /B /ON 2^>nul') do (
if exist "%%I\%%J" (
echo Extracting "%%I\%%J" ...
"%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%%I\%%J" "%%I\"
if errorlevel 1 (
set "ArchiveFile=%%I\%%J"
>>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
) else (
set "#%%~nxI=%%I"
set "ArchiveExtracted=1"
echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
if errorlevel 1 ( del /F "%%I\%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%%I\%%~n#.part*%%~xJ"
)
)
)
)
)
if defined ArchiveExtracted (
md "%SourceFolder%\done" 2>nul
if exist "%SourceFolder%\done\" (
for /F "tokens=2 delims==" %%I in ('set #') do move /Y "%%I" "%SourceFolder%\done\"
)
)
endlocal
注意: WinRAR 版本5.70不支持将 ZIP 存档中提取文件的文件名写入提取日志文件。帮助页面 Switch -LOG [fmt] [= name]-将名称写入日志文件中。
最后,如果已成功提取然后删除了任何存档,则批处理文件会将存在以#
开头的环境变量的所有文件夹移动到父源目录中的子目录done
中。因此,无法成功提取至少一个归档文件的子目录将在文件夹移动时被忽略,而没有归档文件的子目录也将被忽略。如果最终目标目录不是父源目录的子目录,则代码可能会更容易。
另一个变种,可在完成档案提取后立即移动文件夹。在这种情况下,有必要使用捕获的子目录名称列表,因为在外部 FOR 循环的循环迭代过程中,子目录的列表会更改。 FINDSTR 用于从子目录名称列表中过滤出文件夹done
。
此批处理文件等待用户选择,以在两秒钟后自动选择 n o来中断执行。因此,批处理作业可以被用户安全地中断。通过使用参数/noprompt
启动批处理文件可以避免出现此提示。
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PromptForBreak="
if /I "%~1" == "/noprompt" set "PromptForBreak=rem"
set "SourceFolder=C:\Test"
set "LogExtract=%SourceFolder%\ExtractionLog.txt"
set "LogError=%SourceFolder%\ErrorLog.txt"
del /Q "%LogExtract%" "%LogError%" 2>nul
for /F "eol=| delims=" %%I in ('dir "%SourceFolder%\*" /AD-H /B /ON 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /C:done') do (
set "ArchiveExtracted="
for /F "eol=| delims=" %%J in ('dir "%SourceFolder%\%%I\*.rar" "%SourceFolder%\%%I\*.zip" /A-D-H /B /ON 2^>nul') do (
if exist "%SourceFolder%\%%I\%%J" (
echo Extracting "%SourceFolder%\%%I\%%J" ...
"%ProgramFiles%\WinRAR\WinRAR.exe" x -cfg- -ibck -logpfu="%LogExtract%" -o+ -y -- "%SourceFolder%\%%I\%%J" "%SourceFolder%\%%I\"
if errorlevel 1 (
set "ArchiveFile=%SourceFolder%\%%I\%%J"
>>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
) else (
set "ArchiveExtracted=1"
echo %%~nJ| %SystemRoot%\System32\findstr.exe /I /R "\.part[0123456789][0123456789]*$" >nul
if errorlevel 1 ( del /F "%SourceFolder%\%%I\%%J" ) else for %%# in ("%%~nJ") do del /F /Q "%SourceFolder%\%%I\%%~n#.part*%%~xJ"
)
)
)
if defined ArchiveExtracted (
md "%SourceFolder%\done" 2>nul
if exist "%SourceFolder%\done\" move /Y "%SourceFolder%\%%I" "%SourceFolder%\done\"
%PromptForBreak% %SystemRoot%\System32\choice.exe /C NY /N /T 2 /D N /M "Break execution [N/Y]? "
%PromptForBreak% if errorlevel 2 goto EndBatch
)
)
:EndBatch
endlocal
要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。
call /?
del /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
if /?
md /?
move /?
set /?
setlocal /?