在不导入和导出文件的情况下进行扩展存档

时间:2019-11-29 00:02:32

标签: powershell zip

在处理.zip个文件(Expand-Archive)时,如何停止导出文件并将其导入Powershell中?

我当前正在使用一个临时文件夹来提取.zip文件。 是否有一个变量或我错过的东西比下面的解决方案更好?

$filename = 'foobar'
$Zip_in_Bytes | Set-Content -Encoding Byte -Path "C:\temp\filename.zip"
Expand-Archive -Path "C:\temp\filename.zip" -DestinationPath "C:\temp\" -Force
[xml]$xml = Get-Content -Path "C:\temp\filename.xml"

Remove-Item "C:\temp\filename.zip"
Remove-Item "C:\temp\filename.xml"

Expand-Archive仅支持路径参数,不支持对象 有没有更好的方法来处理.zip文件?

2 个答案:

答案 0 :(得分:1)

使用System.IO.Compression可以处理字节数组和流,而不是临时文件,但是比Expand-Archive处理更多。

编辑:添加了Get-ZipEntryContentAdd-ZipEntry示例调用,并调整了参数,使$ZipFilePath是可选的。

@( 'System.IO.Compression','System.IO.Compression.FileSystem') | % { [void][System.Reflection.Assembly]::LoadWithPartialName($_) }

function Get-ZipEntryContent(#returns the bytes of the first matching entry 
  [string] $ZipFilePath, #optional - specify a ZipStream or path 
  [IO.Stream] $ZipStream = (New-Object IO.FileStream($ZipFilePath, [IO.FileMode]::Open)),
  [string] $EntryPath){
    $ZipArchive = New-Object IO.Compression.ZipArchive($ZipStream, [IO.Compression.ZipArchiveMode]::Read)
    $buf = New-Object byte[] (0) #return an empty byte array if not found
    $ZipArchive.GetEntry($EntryPath) | ?{$_} | %{ #GetEntry returns first matching entry or null if there is no match
        $buf = New-Object byte[] ($_.Length)
        Write-Verbose "     reading: $($_.Name)"
        $_.Open().Read($buf,0,$buf.Length)
    }
    $ZipArchive.Dispose()
    $ZipStream.Close()
    $ZipStream.Dispose()
    return $buf 
}


function Add-ZipEntry(#Adds an entry to the $ZipStream. Sample call: Add-ZipEntry -ZipFilePath "$PSScriptRoot\temp.zip" -EntryPath Test.xml -Content ([text.encoding]::UTF8.GetBytes("Testing"))
  [string] $ZipFilePath, #optional - specify a ZipStream or path 
  [IO.Stream] $ZipStream = (New-Object IO.FileStream($ZipFilePath, [IO.FileMode]::OpenOrCreate)),
  [string] $EntryPath, 
  [byte[]] $Content, 
  [switch] $OverWrite, #if specified, will not create a second copy of an existing entry 
  [switch] $PassThru ){#return a copy of $ZipStream
    $ZipArchive = New-Object IO.Compression.ZipArchive($ZipStream, [IO.Compression.ZipArchiveMode]::Update, $true)
    $ExistingEntry = $ZipArchive.GetEntry($EntryPath) | ?{$_} 
    If($OverWrite -and $ExistingEntry){
        Write-Verbose "    deleting existing $($ExistingEntry.FullName)"
        $ExistingEntry.Delete()
    }
    $Entry = $ZipArchive.CreateEntry($EntryPath)
    $WriteStream = New-Object System.IO.StreamWriter($Entry.Open())
    $WriteStream.Write($Content,0,$Content.Length)
    $WriteStream.Flush()
    $WriteStream.Dispose()
    $ZipArchive.Dispose()
    If($PassThru){
        $OutStream = New-Object System.IO.MemoryStream
        $ZipStream.Seek(0, 'Begin') | Out-Null
        $ZipStream.CopyTo($OutStream)
    }
    $ZipStream.Close()
    $ZipStream.Dispose()
    If($PassThru){$OutStream}
}

下面是一个如何在内存中完全调用Add-ZipEntryGet-ZipEntryContent函数的示例:

$NewZipStream = Add-ZipEntry -ZipStream (New-Object IO.MemoryStream) -EntryPath Test.xml -Content ([text.encoding]::UTF8.GetBytes("<xml><test>1</test>")) -PassThru
$bytes = Get-ZipEntryContent -ZipStream $NewZipStream -EntryPath 'Test.xml'
[text.encoding]::UTF8.GetString($bytes)

答案 1 :(得分:0)

尽管Expand-Archive不接受对象,但是您可以为其提供对象的字符串属性。例如。 $File.FullName将是String

Get-ChildItem C:\temp\ -Filter "*.zip" | 
    ForEach-Object {
        Expand-Archive -Path $_.FullName -DestinationPath "C:\Temp\Extracted\$($_.BaseName)\"
    }