我想将每个文件夹中存在的ZIP和RAR压缩文件解压缩到命令行中的相应文件夹。此外,我想只在解压缩期间没有错误时删除原始压缩文件。如果提取存档时出错,则应将存档文件名写入错误日志文件,并且应继续提取下一个存档文件的提取过程。
我想在解压缩成功后将每个文件夹移动到done
文件夹。但批处理文件不应移动不包含任何存档文件的文件夹。
之前:
C:
│
└─test
├─AAAA
│ XXXX.rar
│ XXXX.jpg
│
├─BBBB
│ XXXX.zip
│ XXXX.jpg
│
├─CCCC(error_file)
│ XXXX.rar
│ XXXX.jpg
│
├─DDDD
│ XXXX.part1.rar
│ XXXX.part2.rar
│ XXXX.jpg
│
└─EEEE
XXXX.jpg
后:
C:
│
└─test
├─done
│ │
│ │
│ ├─AAAA
│ │ XXXX.doc
│ │ XXXX.jpg
│ │
│ ├─BBBB
│ │ XXXX.doc
│ │ XXXX.jpg
│ │
│ └─DDDD
│ XXXX.doc
│ XXXX.jpg
│
├─CCCC(error_file)
│ XXXX.rar
│ XXXX.jpg
│
└─EEEE
XXXX.jpg
以下代码取自Mofi从问题的初始版本的答案并由我改编而来。
@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- -logpfu="%LogExtract%" -or -- "%%I\%%J" "%%I\"
if errorlevel 1 (
set "ArchiveFile=%%I\%%J"
>>"%LogError%" call echo Error %%ErrorLevel%% on extracting "%%ArchiveFile%%"
) else (
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 /I not "%%~nxI" == "done" if not exist "%%I\*.rar" if not exist "%%I\*.zip" move /Y "%%I" "%SourceFolder%\done\"
)
)
endlocal
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帮助页面WinRAR退出代码列表中所述。
如果没有100%成功提取由值为ArchiveFile
的WinRAR退出指示的存档文件,则将归档文件名分配给环境变量0
,然后输出错误消息行,将WinRAR的退出代码和文件名输入到错误日志文件。根据Windows命令处理器在启动批处理文件处理时定义的字符编码和代码页对错误日志文件进行编码。
环境变量ErrorLevel
和ArchiveFile
在每一侧都引用了两个百分号,因为Windows命令处理器在解析整个命令块之前已经替换,只需%%
执行外部所有%
。命令CALL导致在执行ECHO之前对ECHO命令行进行第二次解析,这导致将%Errorlevel%
替换为此环境变量的当前值以及当前存档文件名的%ArchiveFile%
。
没有命令CALL的像Qazxswpoi这样的ECHO线将导致用外部FOR执行所有这意味着用echo Error %ErrorLevel% on extracting "%ArchiveFile%"
替换%ErrorLevel%
环境变量ErrorLevel
的当前值,并用空字符串替换0
当然没有用。
归档文件名分配给环境变量%ArchiveFile%
,并像ArchiveFile
一样引用,以处理像ErrorLevel
正确的文件名。
在多卷存档上出现错误时,不会删除任何RAR存档部件,从而导致多次提取多卷存档的所有卷,并将多卷存档文件的每个部分写入错误日志文件。
成功提取单个存档文件时,将删除存档文件,并且在成功提取多卷存档时,将删除多卷存档的所有部分。此外,使用Archive%20!Important!.rar
和子目录名称将环境变量设置为环境变量名称,将子目录的完整路径设置为值,以记住哪些子目录包含至少一个成功提取的存档以便稍后移动它。这个简单方法需要没有子目录名称包含等号。
上述代码无法在子目录中的多个* .rar或* .zip文件上的FAT32或ExFAT驱动器上运行。在这种情况下,必须在后台使用#
启动的单独命令进程中使用FOR执行的命令DIR,并捕获输出存档文件名。然后内部FOR运行时,在循环迭代期间未修改的归档文件名列表由于删除FAT32和ExFAT驱动器上的归档文件而导致。
如果存档文件包含自身* .rar或* .zip文件,则不需要提取此备用批处理文件,因为它可能会在上面的批处理文件代码中发生。
因此,第二批代码比第一批代码更安全。
%ComSpec% /C
注意:WinRAR版本5.70不支持将解压缩文件的文件名从ZIP存档写入提取日志文件。这在帮助页面顶部有文档Switch -LOG [fmt] [= name] - 将名称写入日志文件。
最后,如果成功提取并删除了任何存档,批处理文件会将所有以@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
开头的环境变量存在的文件夹移动到父源目录中的子目录#
中。因此,在文件夹移动以及没有存档文件的子目录中,将忽略未成功提取至少一个存档的子目录。如果最终目标目录不是父源目录的子目录,则代码可能更容易。
在归档提取完成后立即移动文件夹的另一个变体。在这种情况下,必须使用捕获的子目录列表列表,因为在外部FOR循环的循环迭代期间子目录列表会发生更改。 FINDSTR用于从子目录名称列表中过滤出文件夹done
。
此批处理文件等待用户选择中断执行,并在两秒后自动选择否。因此,用户可以安全地打破批处理作业。通过使用参数done
启动批处理文件可以避免此提示。
/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 /?