如何使用WinRAR命令行将多个档案提取到每个文件夹?

时间:2019-04-13 09:17:45

标签: windows batch-file zip rar winrar

我想在命令行中将每个文件夹中存在的ZIP和RAR存档提取到相应的文件夹中。此外,我只想在解压缩过程中没有错误的情况下删除原始压缩文件。如果提取存档时出错,则应将存档文件名写入错误日志文件,并且提取过程应继续下一个存档文件。

我想在解压缩成功后将每个文件夹移至xsl:choose文件夹。但是批处理文件不应移动不包含任何存档文件的文件夹。

之前:

Part

之后:

Part

下面的代码是从Mofi从问题的初始版本中得到的答案,并由我改编而成的。

done

1 个答案:

答案 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 提取每个存档文件

  • 保持目录结构,
  • 忽略标准配置,
  • 在后台,这意味着最小化了系统托盘,
  • 将从 RAR 存档中提取的文件记录到Unicode编码(无BOM的UTF-16 Little Endian)提取日志文件中,
  • 覆盖所有现有文件,
  • 假设所有查询(如出现错误)为

WinRAR 自动提取多卷存档的所有卷。

WinRAR 的错误值为更大或等于 1退出,如帮助页面 WinRAR 的帮助中所述< em> WinRAR退出代码列表。

如果未成功提取由 WinRAR 退出且值为ArchiveFile的归档文件,归档文件名将分配给环境变量0,并且接下来,输出一条错误消息行,将 WinRAR 的退出代码和文件名写入错误日志文件。错误日志文件的编码取决于Windows命令处理器在开始批处理文件处理时定义的字符编码和代码页。

环境变量ErrorLevelArchiveFile的两边都用两个百分号引用,因为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 /?