我试图使用.NET类而不是本机compress-archive来压缩多个目录(每个目录都包含子目录和文件),因为compress-archive给了我偶尔的OutOfMemory异常。
一些文章告诉我.NET类,它提供了一种更优化的方法。
我的tools目录$toolsDir = 'C:\Users\Public\LocalTools'有多个需要压缩的目录(请注意,所有内容都是一个目录,而不是文件)--哪个目录与regex模式匹配,如代码中所示。
下面是我的代码:
$cmpname = $env:computername
$now = $(Get-Date -Format yyyyMMddmmhhss)
$pattern = '^(19|[2-9][0-9])\d{2}\-(0?[1-9]|1[012])\-(0[1-9]|[12]\d|3[01])T((?:[01]\d|2[0-3])\;[0-5]\d\;[0-5]\d)\.(\d{3}Z)\-' + [ regex ]::Escape($cmpname)
$toolsDir = 'C:\Users\Public\LocalTools'
$destPathZip = "C:\Users\Public\ToolsOutput.zip"
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$CompressionLevel = [ System.IO.Compression.CompressionLevel ]::Optimal
$IncludeBaseDirectory = $false
$stream = New-Object System.IO.FileStream($destPathZip , [ System.IO.FileMode ]::OpenOrCreate)
$zip = New-Object System.IO.Compression.ZipArchive($stream , 'update')
$res = Get-ChildItem "${toolsDir}" | Where-Object {$_ .Name -match "${pattern}"}
if ($res -ne $null) {
foreach ($dir in $res) {
$source = "${toolsDir}\${dir}"
[ System.IO.Compression.ZipFileExtensions ]::CreateEntryFromFile($destPathZip , $source , (Split-Path $source -Leaf), $CompressionLevel)
}
}
else {
Write-Host "Nothing to Archive!"
} 上面的代码给出了这个错误:


当我研究[ System.IO.Compression.ZipFileExtensions ]::CreateEntryFromFile时,它被用来将files添加到已经创建的zip文件中。这就是我得到错误的原因吗?
我也尝试了[ System.IO.Compression.ZipFile ]::CreateFromDirectory($source , $destPathZip , $CompressionLevel, $IncludeBaseDirectory)而不是[ System.IO.Compression.ZipFileExtensions ]::CreateEntryFromFile($destPathZip , $source , (Split-Path $source -Leaf), $CompressionLevel)
这给了我"The file 'C:\Users\Public\ToolsOutput.zip' already exists错误。
如何更改代码,以便在zip文件中添加多个目录。
发布于 2022-03-09 12:29:07
当前,您的代码有三个问题:
传递给purpose.
CreateEntryFromFile的ZipArchive对象--在您的示例中,您将希望传递已经为该CreateEntryFromFile()创建的$zip,每个调用只为一个文件创建一个条目--以便重新创建一个完整的目录子结构,以计算每个文件的正确入口路径,例如。subdirectory/subsubdirectory/file.exeZipArchive和底层文件流实例,以便将数据持久化到磁盘上。为此,您需要一个try/finally语句.此外,如果没有要存档的文件,则无需创建该文件:)
$cmpname = $env:computername
$pattern = '^(19|[2-9][0-9])\d{2}\-(0?[1-9]|1[012])\-(0[1-9]|[12]\d|3[01])T((?:[01]\d|2[0-3])\;[0-5]\d\;[0-5]\d)\.(\d{3}Z)\-' + [regex]::Escape($cmpname)
$toolsDir = 'C:\Users\Public\LocalTools'
$destPathZip = "C:\Users\Public\ToolsOutput.zip"
Add-Type -AssemblyName System.IO.Compression
Add-Type -AssemblyName System.IO.Compression.FileSystem
$CompressionLevel = [System.IO.Compression.CompressionLevel]::Optimal
$res = Get-ChildItem -LiteralPath $toolsDir | Where-Object { $_.Name -match $pattern }
if ($res) {
try {
# Create file + zip archive instances
$stream = New-Object System.IO.FileStream($destPathZip, [System.IO.FileMode]::OpenOrCreate)
$zip = New-Object System.IO.Compression.ZipArchive($stream, [System.IO.Compression.ZipArchiveMode]::Update)
# Discover all files to archive
foreach ($file in $res |Get-ChildItem -File -Recurse) {
$source = $dir.FullName
# calculate correct relative path to the archive entry
$relativeFilePath = [System.IO.Path]::GetRelativePath($toolsDir, $source)
$entryName = $relativeFilePath.Replace('\', '/')
# Make sure the first argument to CreateEntryFromFile is the ZipArchive object
[System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($zip, $source, $entryName, $CompressionLevel)
}
}
finally {
# Clean up in reverse order
$zip, $stream | Where-Object { $_ -is [System.IDisposable] } | ForEach-Object Dispose
}
}
else {
Write-Host "Nothing to Archive!"
}调用Dispose() on $zip将导致它刷新对底层文件流的任何未写入的修改,并释放它可能获得的任何其他文件句柄,而在底层文件流上调用Dispose()则会将这些更改刷新到磁盘并关闭文件句柄。
https://stackoverflow.com/questions/71407463
复制相似问题