【问题标题】:Most elegant way to extract a directory from a zipfile using PowerShell?使用 PowerShell 从 zipfile 中提取目录的最优雅方法?
【发布时间】:2016-10-30 01:35:11
【问题描述】:

我需要从 zipfile 中解压缩特定目录。

例如,从 zipfile 'c:\tmp\test.zip' 中提取目录 'test\etc\script' 并将其放在 c:\tmp\output\test\etc\script 中。

下面的代码有效,但有两个怪癖:

  • 虽然我已经知道路径('c:\tmp\test.zip\test\etc\script'),但我需要在 zip 文件(函数 finditem)中递归查找目录('script')

  • 使用 CopyHere 我需要手动确定目标目录,特别是 'test\etc' 部分

有更好的解决方案吗?谢谢。

代码:

function finditem($items, $itemname)
{
  foreach($item In $items)
  {
    if ($item.GetFolder -ne $Null)
    {
      finditem $item.GetFolder.items() $itemname
    }
    if ($item.name -Like $itemname)
    {
        return $item
    } 
  } 
} 

$source = 'c:\tmp\test.zip'
$target = 'c:\tmp\output'

$shell = new-object -com shell.application

# find script folder e.g. c:\tmp\test.zip\test\etc\script
$item = finditem $shell.NameSpace($source).Items() "script"

# output folder is c:\tmp\output\test\etc
$targetfolder = Join-Path $target ((split-path $item.path -Parent) -replace '^.*zip')
New-Item $targetfolder -ItemType directory -ErrorAction Ignore

# unzip c:\tmp\test.zip\test\etc\script to c:\tmp\output\test\etc
$shell.NameSpace($targetfolder).CopyHere($item)

【问题讨论】:

  • 我知道位置,所以不得不递归查找目录看起来很可惜。 .NET 4.5 代码有效,但我不愿意添加另一个先决条件。
  • 好吧,那么可以避免搜索和另一个先决条件,看我的回答。

标签: powershell


【解决方案1】:

我不知道最优雅的,但安装了 .Net 4.5 后,您可以使用 System.IO.Compression 命名空间中的 ZipFile 类:

[Reflection.Assembly]::LoadWithPartialName('System.IO.Compression.FileSystem') | Out-Null

$zipfile = 'C:\path\to\your.zip'
$folder  = 'folder\inside\zipfile'
$dst     = 'C:\output\folder'

[IO.Compression.ZipFile]::OpenRead($zipfile).Entries | ? {
  $_.FullName -like "$($folder -replace '\\','/')/*"
} | % {
  $file   = Join-Path $dst $_.FullName
  $parent = Split-Path -Parent $file
  if (-not (Test-Path -LiteralPath $parent)) {
    New-Item -Path $parent -Type Directory | Out-Null
  }
  [IO.Compression.ZipFileExtensions]::ExtractToFile($_, $file, $true)
}

ExtractToFile()的第三个rd参数可以省略。如果存在,它定义是否将覆盖现有文件。

【讨论】:

  • 谢谢!我确实必须将 -like 末尾的 /* 更改为 /*.* ,否则它也会尝试处理目录本身,从而导致异常。
  • 如果您使用ExtractToDirectory,这将更加优雅。 ;)
  • @jpmc26 OP 不想提取 zip 文件的全部内容。
  • @AnsgarWiechers 哎呀。我的错。
【解决方案2】:

只要知道 zip 中的文件夹位置,就可以简化原始代码:

$source = 'c:\tmp\test.zip'  # zip file
$target = 'c:\tmp\output'    # target root
$folder = 'test\etc\script'  # path in the zip

$shell = New-Object -ComObject Shell.Application

# find script folder e.g. c:\tmp\test.zip\test\etc\script
$item = $shell.NameSpace("$source\$folder")

# actual destination directory
$path = Split-Path (Join-Path $target $folder)
if (!(Test-Path $path)) {$null = mkdir $path}

# unzip c:\tmp\test.zip\test\etc\script to c:\tmp\output\test\etc\script
$shell.NameSpace($path).CopyHere($item)

【讨论】:

  • 这比 ExtractToFile 慢
  • 这样其他人就不会遇到我同样的问题。尝试使用它访问 nupkg 文件时,您必须将文件重命名为 .zip 才能正确解释它。
【解决方案3】:

Windows PowerShell 5.0(包含在 Windows 10 中)本机支持使用 Expand-Archive cmdlet 提取 ZIP 文件:

Expand-Archive -Path Draft.Zip -DestinationPath C:\Reference

【讨论】:

  • ...Windows 10 包括 PowerShell 5.0
  • 但问题要求特别提取 zip 的子文件夹。
猜你喜欢
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 1970-01-01
  • 2017-06-06
  • 1970-01-01
  • 2010-11-04
  • 2023-04-08
相关资源
最近更新 更多