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 提取每个存档文件
- 保持目录结构,
- 忽略标准配置,
- 在后台,这意味着最小化到系统托盘,
- 将提取的文件从 RAR 存档记录到 Unicode 编码(UTF-16 Little Endian,无 BOM)提取日志文件,
- 覆盖所有已经存在的文件,
- 假设所有查询都是,例如出现错误。
WinRAR 自动提取多卷存档的所有卷。
WinRAR 以 大于或等于 1 的值退出,如帮助页面上 WinRAR 的帮助中所述的错误 WinRAR 退出代码列表。
存档文件名分配给环境变量ArchiveFile,以防 WinRAR 退出指示的存档文件未 100% 成功提取,值为0,然后出现错误消息行是将 WinRAR 的退出代码和文件名写入错误日志文件的输出。错误日志文件的编码取决于 Windows 命令处理器在开始批处理文件处理时定义的字符编码和代码页。
环境变量ErrorLevel 和ArchiveFile 在每一边都用两个百分号引用,因为Windows 命令处理器在执行外部FOR 之前已经替换了解析整个命令块所有%% 由只是%。命令 CALL 会导致在执行 ECHO 之前对 ECHO 命令行进行第二次解析,从而将 %Errorlevel% 替换为此环境的当前值变量以及 %ArchiveFile% 当前存档文件名。
像echo Error %ErrorLevel% on extracting "%ArchiveFile%" 这样没有命令CALL 的ECHO 行将导致在外部FOR%ErrorLevel% 替换为环境变量ErrorLevel 的当前值/strong> 完全执行,这意味着使用 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。
此批处理文件等待用户选择中断执行,两秒后自动选择no。因此,用户可以安全地中断批处理作业。这个提示可以通过参数/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 /?