我正在使用下一个代码来下载一些 zip 存档:
$client = new-object System.Net.WebClient
$client.DownloadFile("https://chromedriver.storage.googleapis.com/$LatestChromeRelease/chromedriver_win32.zip","D:\MyFolder.zip")
结果我得到了包含所需文件的 ZIP 存档“MyFolder.zip”(让我们想象一下“test.txt”)。
如何将这个特定文件从 ZIP 存档提取到给定文件夹中?
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
}
}
使用 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()
}
}
备注:
Convert-Path
。 .NET 框架有自己的当前目录,该目录不一定与 PowerShell 的目录匹配。使用 Convert-Path
我们转换为绝对路径,因此 .NET 的当前目录不再相关。.Where
和 .ForEach
是 PowerShell 内在方法,可用于所有对象。它们类似于 Where-Object
和 ForEach-Object
命令,但效率更高。一旦我们找到文件,将 'First'
作为第二个参数传递给 .Where
就会停止搜索。.Where
始终输出一个集合,即使只有一个元素匹配。这与 Where-Object
相反,如果只有单个元素匹配,则返回 单个对象。因此,在将其传递给函数 $foundFile[ 0 ]
时,我们必须编写 ExtractToFile
,而不是仅仅将 $foundFile
写为数组。