Ser*_*mos 8 powershell zip unzip system.io.compression
我正在使用下面的代码下载一些 zip 存档:
$client = new-object System.Net.WebClient
$client.DownloadFile("https://chromedriver.storage.googleapis.com/$LatestChromeRelease/chromedriver_win32.zip","D:\MyFolder.zip")
Run Code Online (Sandbox Code Playgroud)
结果我得到了包含所需文件的 ZIP 存档“MyFolder.zip”(让我们想象一下“test.txt”)。
如何将这个特定文件从 ZIP 存档提取到给定文件夹中?
zet*_*t42 10
PowerShell 4+ 有一个Expand-Archive命令,但从 PS 7.2.3 开始,它只能完全提取存档。因此,将其解压到临时目录并复制您感兴趣的文件。
如果您有 PS 5.1+ 可用,请向下滚动以获取使用 .NET 类的更高效的解决方案。
$archivePath = 'D:\MyFolder.zip'
$destinationDir = 'D:\MyFolder'
# Relative path of file in ZIP to extract.
$fileToExtract = 'test.txt'
# Create destination dir if not exist.
$null = New-Item $destinationDir -ItemType Directory -Force
# Create a unique temporary directory
$tempDir = Join-Path ([IO.Path]::GetTempPath()) ([System.Guid]::NewGuid().ToString('n'))
$null = New-Item $tempDir -ItemType Directory
try {
# Extract archive to temp dir
Expand-Archive -LiteralPath $archivePath -DestinationPath $tempDir
# Copy the file we are interested in
$tempFilePath = Join-Path $tempDir $fileToExtract
Copy-Item $tempFilePath $destinationDir
}
finally {
# Remove the temp dir
if( Test-Path $tempDir ) {
Remove-Item $tempDir -Recurse -Force -EA Continue
}
}
Run Code Online (Sandbox Code Playgroud)
使用PS 5.1+,您可以使用.NET 类直接提取单个文件(无需提取整个存档):
# Load required .NET assemblies. Not necessary on PS Core 7+.
Add-Type -Assembly System.IO.Compression.FileSystem
$archivePath = 'D:\MyFolder.zip'
$destinationDir = 'D:\MyFolder'
# Relative path of file in ZIP to extract.
# Use FORWARD slashes as directory separator, e. g. 'subdir/test.txt'
$fileToExtract = 'test.txt'
# Create destination dir if not exist.
$null = New-Item $destinationDir -ItemType Directory -Force
# Convert (possibly relative) paths for safe use with .NET APIs
$resolvedArchivePath = Convert-Path -LiteralPath $archivePath
$resolvedDestinationDir = Convert-Path -LiteralPath $destinationDir
$archive = [IO.Compression.ZipFile]::OpenRead( $resolvedArchivePath )
try {
# Locate the desired file in the ZIP archive.
# Replace $_.Fullname by $_.Name if file shall be found in any sub directory.
if( $foundFile = $archive.Entries.Where({ $_.FullName -eq $fileToExtract }, 'First') ) {
# Combine destination dir path and name of file in ZIP
$destinationFile = Join-Path $resolvedDestinationDir $foundFile.Name
# Extract the file.
[IO.Compression.ZipFileExtensions]::ExtractToFile( $foundFile[ 0 ], $destinationFile )
}
else {
Write-Error "File not found in ZIP: $fileToExtract"
}
}
finally {
# Dispose the archive so the file will be unlocked again.
if( $archive ) {
$archive.Dispose()
}
}
Run Code Online (Sandbox Code Playgroud)
笔记:
Convert-Path将可能是相对路径的 PowerShell 路径传递给 .NET API 时应使用。.NET 框架有自己的当前目录,该目录不一定与 PowerShell 的目录匹配。使用Convert-Path我们转换为绝对路径,因此 .NET 的当前目录不再相关。.Where和是可用于所有对象的.ForEachPowerShell内部方法。它们与Where-Object和ForEach-Object命令类似,但效率更高。一旦我们找到文件,作为第二个参数传递就停止搜索'First'。.Where.Where始终输出一个集合。这与如果只有单个元素匹配则Where-Object返回单个对象相反。因此,我们必须$foundFile[ 0 ]在将其传递给 function 时编写ExtractToFile,而不仅仅是$foundFilethis 将是一个数组。