首页 > 解决方案 > 使用 7zip 提取嵌套 zip 并在成功提取后删除 zip 的批处理文件

问题描述

我有一个装满 zip 文件的文件夹。这些 zip 文件有时包含 zip 文件,有时在其中包含 zip 文件,依此类推。我正在尝试编写一个批处理文件,我可以将其粘贴到包含所有 zip 的顶级文件夹中,当它运行时,它将解压缩所有嵌套的 zip 文件,并在子目录中,一直向下,并删除一次 zip它们已被成功提取。需要保留完整的文件路径。如果出现错误并且无法提取文件,则不应将其删除,并且需要将文件和文件路径打印到文本文件中。

到目前为止,我有这个:

@ECHO ON

SET source=%cd%
FOR /F "TOKENS=*" %%F IN ('DIR /S /B "%source%\*.zip"') DO "C:\Program Files\7-Zip\7z.exe" x "%%~fF" -o"%%~pF\"
EXIT

我可以将其放入文件夹并运行,它将解压缩第一级拉链,但没有嵌套的拉链。这是第一个障碍。

下一个障碍是删除成功提取的 zip。最后,不要删除任何无法提取的 zip,并将其名称和/或路径打印到文本文件中。

任何建议或代码块表示赞赏。或者,如果有更好的方法可以完全做到这一点。

**** 更新 ****

Mofi 发布了一个答案,除了一件之外,它看起来像是在工作:

一个ZIP解压的时候,需要解压到同名的文件夹,所以我还是可以按照结构来的。

起始示例:

[Top Level Folder Holding Zips] (folder)
--ExampleZip.zip
---FileInZip.txt
---FileinZip2.txt
--ExampleZip2.zip
---Folder1 (folder)
----ExampleZip3.zip
-----FileinZip3.txt
-----FileinZip4.txt
---ExampleZip4.zip
----FileinZip5.txt
----FileinZip6.txt

需要变成这样:

[Top Level Folder Holding Zips] (folder)
--ExampleZip (folder)
---FileInZip.txt
---FileinZip2.txt
--ExampleZip2 (folder)
---Folder1 (folder)
----ExampleZip3 (folder)
-----FileinZip3.txt
-----FileinZip4.txt
---ExampleZip4 (folder)
----FileinZip5.txt
----FileinZip6.txt

所以完整的结构仍然可见。

我认为这个问题的最佳答案显示了我需要包含的内容:将zip 内容提取到与 zip 文件同名的目录中,保留目录结构

这部分:


SET "filename=%~1"
SET dirName=%filename:~0,-4%

7z x -o"%dirName%" "%filename%"

需要在某个地方砸碎。或者似乎应该有一个用于 7Zip 的开关来执行此操作,因为您可以从上下文菜单中使用“提取到 *”来执行此操作,我认为这就是“使用完整路径提取”命令所做的,但必须有一些事情要做使用 -o 开关,指定输出路径?如何将输出路径指定为与输入 zip 同名的文件夹?或者将我链接的那个问题的答案与 Mofi 的答案合并?

***再次更新***

我认为批处理文件忽略名称中带有下划线的 ZIP 文件存在问题,但这是巧合,它实际上忽略了没有设置存档文件属性的 ZIP 文件。

Mofi 建议了另一种可行的修复方法,但批处理文件未提取需要存档文件属性集的嵌套 zip。

这确实有效,因为我可以手动执行批处理文件几次,它将通过文件夹中的所有内容工作,但循环计算似乎不起作用,或者在批处理文件设置之前计算/终止所有 zip 文件的存档属性?

这是我正在使用的当前版本:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ErrorOutput="
set "LoopCount=20"

rem The current directory is used on batch file being called without
rem a base folder path or with just one or more double quotes.
set "BaseFolder=%~1"
if defined BaseFolder set "BaseFolder=%BaseFolder:"=%"
if not defined BaseFolder set "BaseFolder=%CD%" & goto VerifyFolderPath

rem Make sure the folder path contains backslashes and not forward slashes
rem and does not contain wildcard characters or redirection operators or a
rem horizontal tab character after removing all double quotes.
set "BaseFolder=%BaseFolder:/=\%"
for /F "delims=*?|<>    " %%I in ("%BaseFolder%") do if not "%BaseFolder%" == "%%I" (
    echo ERROR: %~nx0 must be called with a valid folder path.
    echo        "%~1" is not a valid folder path.
    set "ErrorOutput=1"
    goto EndBatch
)

rem Get full folder path in case of the folder was specified with
rem a relative path. If the folder path references the root of a
rem drive like on using "C:\" or just "\", redefine the folder
rem path with full path for root of the (current) drive.
for %%I in ("%BaseFolder%") do set "BaseFolder=%%~fI"

:VerifyFolderPath
rem The base folder path must end with a backslash for verification.
if not "%BaseFolder:~-1%" == "\" set "BaseFolder=%BaseFolder%\"

rem Verify the existence of the folder. The code above processed also
rem folder paths of folders not existing at all and also invalid folder
rem paths containing for example a colon not (only) after drive letter.
if not exist "%BaseFolder%" (
    echo ERROR: Folder "%BaseFolder%" does not exist.
    set "ErrorOutput=1"
    goto EndBatch
)

rem Make sure to process all ZIP files existing in base folder and all
rem its subfolders by setting archive file attribute on all ZIP files.
%SystemRoot%\System32\attrib.exe +A /S "%BaseFolder%*.zip"

rem Process all *.zip files found in base folder and all its subfolders
rem which have the archive file attribute set. *.zip files with archive
rem file attribute not set are ignored to avoid an endless running loop
rem if a ZIP archive file cannot be extracted successfully with reason(s)
rem output by 7-Zip or if the ZIP file cannot be deleted after successful
rem extraction of the archive. The archive extraction loop runs are limited
rem additionally by a loop counter as defined at top of the batch file for
rem 100% safety on prevention of an endless loop execution.

:ExtractArchives
set "ArchiveProcessed="
for /F "delims=" %%I in ('dir "%BaseFolder%*.zip" /AA-D /B /S 2^>nul') do (
    set "ArchiveProcessed=1"
    echo Extracting archive: "%%I"
    "%ProgramFiles%\7-Zip\7z.exe" x -bd -bso0 -o"%%~dpnI\" -spd -y -- "%%I"
@pause
    if errorlevel 255 set "ErrorOutput=1" & goto EndBatch
    if errorlevel 1 (
        set "ErrorOutput=1"
        %SystemRoot%\System32\attrib.exe -A "%%I"
    ) else (
        del /A /F "%%I"
        if exist "%%I" (
            echo ERROR: Failed to delete: "%%I"
            set "ErrorOutput=1"
            %SystemRoot%\System32\attrib.exe -A "%%I"
        )
    )
)
if not defined ArchiveProcessed goto EndBatch
set /A LoopCount-=1
if not LoopCount == 0 goto ExtractArchives

:EndBatch
if defined ErrorOutput echo/& pause
endlocal
echo[
echo[
echo If no errors are displayed above, everything extracted successfully. Remember to delete the batch file once you are done.
@pause

很少有可能有 10 或 20 层嵌套 zip,因此快速而肮脏的修复可能只是以某种方式将整个批处理文件循环 10 或 20 次,除非这是一个坏主意或有更优雅的方法来做。

标签: batch-filecmdzip7zip

解决方案


递归提取所有 ZIP 档案的任务,包括 ZIP 档案内的嵌套 ZIP 档案,可以通过在循环中运行 ZIP 档案文件提取过程直到不再存在 ZIP 文件来实现。但是必须至少考虑两个用例,以避免无休止的运行存档提取循环:

  1. 无论出于何种原因,ZIP 存档文件的提取都会失败。7-Zip输出有关错误原因的信息。不应再次处理此类 ZIP 文件。
  2. 无论出于何种原因,成功提取的 ZIP 文件的删除都会失败。不应再次处理 ZIP 文件。

解决方案是仅处理具有归档文件属性的 ZIP 文件,这些文件由 Windows 在创建、重命名或修改文件时自动完成,并删除每个 ZIP 文件上的归档文件属性,在该文件上提取过程或删除文件未能避免处理ZIP 文件。

存档文件属性设置在目录树上的所有 *.zip 文件上,以便在开始存档文件提取过程之前进行处理,以确保所有现有的 *.zip 文件至少被处理一次。归档文件属性也设置在完全成功处理的 ZIP 归档文件的输出目录中的所有 *.zip 文件上,以确保即使在提取后未设置归档文件属性的 ZIP 文件中的 *.zip 文件也会在下一步处理存档文件提取循环运行。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ErrorOutput="
set "LoopCount=20"

rem The current directory is used on batch file being called without
rem a base folder path or with just one or more double quotes.
set "BaseFolder=%~1"
if defined BaseFolder set "BaseFolder=%BaseFolder:"=%"
if not defined BaseFolder set "BaseFolder=%CD%" & goto VerifyFolderPath

rem Make sure the folder path contains backslashes and not forward slashes
rem and does not contain wildcard characters or redirection operators or a
rem horizontal tab character after removing all double quotes.
set "BaseFolder=%BaseFolder:/=\%"
for /F "delims=*?|<>    " %%I in ("%BaseFolder%") do if not "%BaseFolder%" == "%%I" (
    echo ERROR: %~nx0 must be called with a valid folder path.
    echo        "%~1" is not a valid folder path.
    set "ErrorOutput=1"
    goto EndBatch
)

rem Get full folder path in case of the folder was specified with
rem a relative path. If the folder path references the root of a
rem drive like on using "C:\" or just "\", redefine the folder
rem path with full path for root of the (current) drive.
for %%I in ("%BaseFolder%") do set "BaseFolder=%%~fI"

:VerifyFolderPath
rem The base folder path must end with a backslash for verification.
if not "%BaseFolder:~-1%" == "\" set "BaseFolder=%BaseFolder%\"

rem Verify the existence of the folder. The code above processed also
rem folder paths of folders not existing at all and also invalid folder
rem paths containing for example a colon not (only) after drive letter.
if not exist "%BaseFolder%" (
    echo ERROR: Folder "%BaseFolder%" does not exist.
    set "ErrorOutput=1"
    goto EndBatch
)

rem Make sure to process all ZIP files existing in base folder and all
rem its subfolders by setting archive file attribute on all ZIP files.
%SystemRoot%\System32\attrib.exe +A /S "%BaseFolder%*.zip" >nul

rem Process all *.zip files found in base folder and all its subfolders
rem which have the archive file attribute set. *.zip files with archive
rem file attribute not set are ignored to avoid an endless running loop
rem if a ZIP archive file cannot be extracted successfully with reason(s)
rem output by 7-Zip or if the ZIP file cannot be deleted after successful
rem extraction of the archive. The archive extraction loop runs are limited
rem additionally by a loop counter as defined at top of the batch file for
rem 100% safety on prevention of an endless loop execution.

:ExtractArchives
set "ArchiveProcessed="
for /F "delims=" %%I in ('dir "%BaseFolder%*.zip" /AA-D /B /S 2^>nul') do (
    set "ArchiveProcessed=1"
    echo Extracting archive: "%%I"
    "%ProgramFiles%\7-Zip\7z.exe" x -bd -bso0 -o"%%~dpI" -spd -y -- "%%I"
    if errorlevel 255 set "ErrorOutput=1" & goto EndBatch
    if errorlevel 1 (
        set "ErrorOutput=1"
        %SystemRoot%\System32\attrib.exe -A "%%I"
    ) else (
        %SystemRoot%\System32\attrib.exe +A /S "%%~dpnI\*.zip" >nul
        del /A /F "%%I"
        if exist "%%I" (
            echo ERROR: Failed to delete: "%%I"
            set "ErrorOutput=1"
            %SystemRoot%\System32\attrib.exe -A "%%I"
        )
    )
)
if not defined ArchiveProcessed goto EndBatch
set /A LoopCount-=1
if not LoopCount == 0 goto ExtractArchives

:EndBatch
if defined ErrorOutput echo/& pause
endlocal

注意:"delims=*?|<>批处理文件代码的第 16 行之后和上必须有一个水平制表符,"而不是一系列空格字符,因为从浏览器窗口复制代码并将代码粘贴到文本编辑器窗口后会有。

批处理文件用带有命令REM(备注)的行进行注释。应该阅读这些注释以理解代码,然后可以删除这些注释以通过 Windows 命令处理器更有效地执行批处理文件。

代码中使用的7-Zip开关通过双击文件打开的7-Zip帮助或从启动的7-Zip的 GUI 窗口中7-zip.chm打开帮助来解释。在帮助选项卡上的内容展开列表项命令行版本并单击列表项开关以显示帮助页面命令行开关以及当前使用的7-Zip版本支持的所有开关。

批处理文件可以使用文件夹路径作为参数执行,以处理此文件夹及其所有子文件夹中的所有 ZIP 文件。因此,可以向发送到Windows 文件资源管理器的上下文菜单添加一个快捷方式文件,该文件运行批处理文件,并将Windows 文件资源管理器传递给批处理文件的文件夹路径作为第一个参数。也可以将批处理文件注册为DirectoryWindows 注册表中的上下文菜单选项,以便能够从支持目录的 Windows 上下文菜单处理程序的任何应用程序中轻松运行批处理文件。

编辑问题后编辑:运行7-Zip的命令行可以修改为:

"%ProgramFiles%\7-Zip\7z.exe" x -bd -bso0 -o"%%~dpnI\" -spe -spd -y -- "%%I"

使用此命令行将每个 ZIP 文件提取到 ZIP 文件的文件夹中的子文件夹中,该文件夹的名称为 ZIP 文件,因为替换-o"%%~dpI"-o"%%~dpnI\". 如果 ZIP 文件在顶层包含与 ZIP 文件同名的文件夹,则附加的7-Zip开关可避免重复文件夹名称。-spe因此,如果Example3.zip在顶层包含文件夹Example3,则文件将被提取到文件夹Example3而不是文件夹Example3\Example3,因为它会在不使用选项的情况下发生-spe

要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • attrib /?
  • call /?
  • dir /?
  • echo /?
  • endlocal /?
  • for /?
  • goto /?
  • if /?
  • rem /?
  • set /?
  • setlocal /?

阅读有关使用命令重定向运算符的Microsoft 文档,了解2>nul. 当 Windows 命令解释器在执行命令FOR之前在后台启动的单独命令进程中执行嵌入式命令行时,重定向操作符>必须^FOR命令行上使用脱字符进行转义以被解释为文字字符。dir


推荐阅读