首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >批处理文件使用7zip提取嵌套的7zip并在成功提取后删除7zip

批处理文件使用7zip提取嵌套的7zip并在成功提取后删除7zip
EN

Stack Overflow用户
提问于 2020-07-26 01:31:28
回答 3查看 5.4K关注 0票数 2

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

到目前为止我有这样的想法:

代码语言:javascript
复制
@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。这是第一个障碍。

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

如有任何建议或代码块,我们将不胜感激。或者有更好的方法来做这件事。

*更新*

Mofi贴出了一个看起来很有效的答案,除了一段:

提取ZIP时,需要将其解压到同名文件夹中,这样我仍然可以按照结构进行操作。

开始示例:

代码语言:javascript
复制
[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

需要变成这样:

代码语言:javascript
复制
[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文件同名的目录中,保留目录结构。

本部分:

代码语言:javascript
复制
SET "filename=%~1"
SET dirName=%filename:~0,-4%

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

一定要在那里被砸碎。或者,应该有一个用于7Zip的开关,因为您可以从上下文菜单中使用“Extractto*”来实现这一点,我认为这就是“”命令所做的,但这必须与-o开关有关,并指定输出路径?如何将输出路径指定为与输入压缩名称相同的文件夹?还是把这个问题的答案和莫菲的答案联系起来?

*再次更新*

我认为批处理文件忽略带有下划线的ZIP文件存在问题,但这是一个巧合,它实际上忽略了没有Archive文件属性集的ZIP文件。

Mofi建议了另一个解决方法,但批处理文件没有提取需要Archive文件属性集的嵌套zip。

这是一种工作,因为我可以手动执行批处理文件几次,并且它可以遍历文件夹中的所有内容,但是循环计算似乎不起作用,或者在批处理文件设置所有zip文件的Archive属性之前正在计算/终止?

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

代码语言:javascript
复制
@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次,除非这是个坏主意,或者有一种更优雅的方法。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-07-26 10:32:29

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

  1. 由于任何原因,ZIP存档文件的提取失败。7-Zip输出有关错误原因的信息。这样的ZIP文件不应该第二次处理。
  2. 删除成功提取的ZIP文件失败的原因是什么。不应再次处理ZIP文件。

解决方案是只处理带有归档文件属性的ZIP文件,这是Windows在创建、重命名或修改文件时自动完成的,并删除了每个ZIP重新文件上的归档文件属性,而在每个ZIP文件上,提取过程或文件删除都未能避免再次处理ZIP文件。

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

代码语言:javascript
复制
@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

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

批处理文件用命令REM (注意事项)的行进行注释。为了理解代码,应该读取这些注释,然后可以删除这些注释,以便由Windows命令处理器更有效地执行批处理文件。

代码中使用的7-Zip开关可以通过双击文件7-zip.chm打开7-Zip或从已启动的7-Zip的GUI窗口中打开帮助来解释。在“帮助”选项卡上,“Content”展开“列表项命令行”版本,然后单击“列表项开关”,以显示“帮助页命令行开关”和当前使用的7-ZipE 233版本所支持的所有开关。

可以使用文件夹路径作为参数来执行批处理文件,以处理该文件夹中的所有ZIP文件及其所有子文件夹。因此,可以在Windows的上下文菜单中添加一个快捷文件,该快捷文件以Windows 传递给批处理文件的文件夹路径作为第一个参数来运行批处理文件。还可以将批处理文件注册为Windows中的Directory上下文菜单选项,以便能够在任何支持目录的Windows菜单处理程序的应用程序中轻松地运行批处理文件。

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

代码语言:javascript
复制
"%ProgramFiles%\7-Zip\7z.exe" x -bd -bso0 -o"%%~dpnI\" -spe -spd -y -- "%%I"

使用此命令行将每个ZIP文件提取到具有ZIP文件名的ZIP文件文件夹中的一个子文件夹中,这是因为用-o"%%~dpnI\"替换了-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 /?

阅读有关使用命令重定向运算符的微软文档,了解2>nul的解释。当>命令解释器在执行命令FOR之前处理此命令行时,必须在FOR命令行上使用插入字符^对重定向运算符进行转义,以便将其解释为文字字符,该命令行使用后台启动的单独命令进程执行嵌入式dir命令行。

票数 2
EN

Stack Overflow用户

发布于 2020-07-26 02:32:41

使用Groovy或Ant

使用Apache Ant或者更好的使用Groovy AntBuilder要容易得多。

例如,这个Groovy脚本将解压缩所有顶级leval zip文件,然后删除它们:

代码语言:javascript
复制
new AntBuilder().with {

  def sourceRoot = '.'

  // Unzip all .zip files in / underneath sourceRoot
  unzip( dest: 'some-folder' ) {
    fileset( dir: sourceRoot ) {
      include name: "**/*.zip"
    }
  }

  // Unzip throws an exception on failure.
  // Delete all .zip files in / underneath sourceRoot
  delete {
    fileset( dir: sourceRoot, includes: '**/*.zip' )
  }
}

您需要继续扫描目标文件夹中的zip,并重复上面的过程,直到所有的东西都解压缩。您可能还会发现使用FileScanner很有用。

如果有任何故障,AntBuilder会抛出一个异常,因此您可以避免删除未能解压缩的档案。AntBuilder还将使用标准的Java机制记录它的进度。你可以告诉它你想要的详细程度,也可以完全压制它。

完整的AntBuilder文档如下:

  • http://docs.groovy-lang.org/latest/html/documentation/ant-builder.html

使用fileScanner

Groovy AntBuilder文档中的示例:

代码语言:javascript
复制
// let's create a scanner of filesets
def scanner = ant.fileScanner {
    fileset(dir:"src/test") {
        include(name:"**/My*.groovy")
    }
}

// now let's iterate over
def found = false
for (f in scanner) {
    println("Found file $f")
    found = true
    assert f instanceof File
    assert f.name.endsWith(".groovy")
}
assert found

把它放在一起

将filesScanner和AntBuilder结合起来完成工作并不是一个巨大的飞跃。我怀疑这将比使用批处理脚本容易得多。

票数 0
EN

Stack Overflow用户

发布于 2020-11-24 08:34:14

最后,成功地编写了一个批处理文件,可以解压缩嵌套的zip,保持存档文件结构完整!

逻辑是,递归运行,直到解压缩所有zip文件。默认的迭代次数为5,可以作为cmd arg "extract.bat 3“传递。可能会更改为while循环,直到命中文件未找到异常为止。最重要的是,提取后删除存档文件,所以,我们不会进入无休止的循环!但是要遵守下面的规则

  1. 它使用7z,确保cmd窗口7z可以运行,即在路径中。
  2. 压缩文件名不能有空格。确保这一点,ext是压缩的
  3. 将zip文件复制到没有其他zip文件的目录中。
  4. 只有.zip ext,您可以将其更改为rar或批处理文件中的任何内容。

这是批处理文件

代码语言:javascript
复制
Rem Nested unzip - @sivakd
echo off
if  "%1"=="" (set iter=5) else (set iter=%1)
echo Running  %iter% iterations
for /l %%x in (1, 1, %iter%) do (
    dir *.zip /s /b > ziplist.txt
    for /F %%f in (ziplist.txt) do (
        7z x %%f -o%%~dpnf -y & del /f %%f
    )
    del ziplist.txt
)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63095250

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档