压缩存档并保留相对路径

Dav*_*nov 6 powershell zip

我在compress-archive做自己想做的事情时充满挑战...

我有一个根项目文件夹,我想将子目录中的某些文件压缩并保留相对路径。例如: / ??? _scripts ??? ??_module1 | | ??? filex.js | ??_module2 | ??? file1.js | ??? file2.txt

因此,我想从根目录创建一个包含的zip文件module2/*,并且我希望保留文件夹结构。我希望我的拉链包含: scripts/module2/file1.js scripts/module2/file2.txt

但是,当我从根文件夹运行此命令时: Compress-Archive -Path "scripts\module2\*" -DestinationPath tmp.zip

压缩文件的内容仅包含: /file1.js /file2.txt

mkl*_*nt0 8

似乎Compress-Archive(从Windows PowerShell v5.1开始)不支持您想要的功能:

定位文件夹将递归地将该文件夹的子树添加到存档中,但仅按目标文件夹的名称(该名称成为存档中的子文件夹)添加,而不是其路径

特别,

Compress-Archive -Path scripts\module2 -DestinationPath tmp.zip
Run Code Online (Sandbox Code Playgroud)

将(递归)存储scripts\module2in 的内容tmp.zip,但不存储archive-internal路径.\scripts\module2,仅存储.\module2-目标文件夹的名称最后一个输入路径组件)。

言下之意是,你必须通过文件夹scripts,而不是以获得所需的存档内部路径,但总是会包括整个子树scripts,因为Compress-Archive报价没有包含/排除机制。


一种繁琐的选择是在$env:TEMP文件夹中重新创建所需的层次结构,然后在其中复制目标文件夹,然后Compress-Archive针对重新创建的层次结构的根目录运行,然后进行清理:

New-Item -Force -ItemType Directory $env:TEMP/scripts
Copy-Item -Recurse -Force scripts/module2 $env:TEMP/scripts
Compress-Archive -LiteralPath $env:TEMP/scripts -DestinationPath tmp.zip
Remove-Item $env:TEMP/Scripts -Recurse -Whatif
Run Code Online (Sandbox Code Playgroud)

否则,您可能可以找到解决方案:

  • 通过直接使用.NET v4.5 + [System.IO.Compression.ZipFile];您可以将其加载到会话中Add-Type -Assembly System.IO.Compression.FileSystem(PowerShell Core中不需要)。

  • 通过使用外部程序(例如7-Zip)


小智 6

我想做到这一点,而不必将完整的结构复制到临时目录。

#build list of files to compress
$files = @(Get-ChildItem -Path .\procedimentos -Recurse | Where-Object -Property Name -EQ procedimentos.xlsx);
$files += @(Get-ChildItem -Path .\procedimentos -Recurse | Where-Object -Property Name -CLike procedimento_*_fs_*_d_*.xml);
$files += @(Get-ChildItem -Path .\procedimentos -Recurse | Where-Object -Property FullName -CLike *\documentos_*_fs_*_d_*);

# exclude directory entries and generate fullpath list
$filesFullPath = $files | Where-Object -Property Attributes -CContains Archive | ForEach-Object -Process {Write-Output -InputObject $_.FullName}

#create zip file
$zipFileName = 'procedimentos.zip'
$zip = [System.IO.Compression.ZipFile]::Open((Join-Path -Path $(Resolve-Path -Path ".") -ChildPath $zipFileName), [System.IO.Compression.ZipArchiveMode]::Create)

#write entries with relative paths as names
foreach ($fname in $filesFullPath) {
    $rname = $(Resolve-Path -Path $fname -Relative) -replace '\.\\',''
    echo $rname
    $zentry = $zip.CreateEntry($rname)
    $zentryWriter = New-Object -TypeName System.IO.BinaryWriter $zentry.Open()
    $zentryWriter.Write([System.IO.File]::ReadAllBytes($fname))
    $zentryWriter.Flush()
    $zentryWriter.Close()
}

# clean up
Get-Variable -exclude Runspace | Where-Object {$_.Value -is [System.IDisposable]} | Foreach-Object {$_.Value.Dispose(); Remove-Variable $_.Name};
Run Code Online (Sandbox Code Playgroud)