PowerShell - 如何在PowerShell中完成/关闭zip文件

5
我想在PowerShell中创建一个zip文件,向其中添加项目,然后在同一脚本中立即以字节形式获取该zip文件的压缩内容。问题是似乎zip应用程序没有将其内容写入文件系统。如何关闭/刷新zip应用程序,以便下一个PowerShell语句可以访问新创建的zip文件?
示例:
new-item -type File test.zip -force
$zip = ( get-item test.zip ).fullname
$app = new-object -com shell.application
$folder = $app.namespace( $zip )
$item = new-item file.txt -itemtype file -value "Mooo" -force
$folder.copyhere( $item.fullname )
dir test.zip # <---- Empty test.zip file
Get-Content -Encoding byte $zip | echo # <-- nothing echoed

"dir test.zip" 显示一个没有内容的zip文件, 因此 Get-Content 返回了空。请注意,这似乎是 copyhere 操作异步行为的问题。如果我在 copyhere 行后睡眠,zip 文件将会被填充。然而,我不知道需要睡眠多长时间,也不想延迟处理。

非常感谢!


我从未在PowerShell中创建过档案,但这看起来根本行不通。 - Joey
1
看这里:http://dotnetzip.codeplex.com/。Inoic.zip是更好的处理zip文件的选择! - CB.
确实可以工作。如果您查看执行这些语句的目录,您会发现已经创建了一个test.zip文件。 - Eric Vasilik
我不想使用任何第三方库。 - Eric Vasilik
你的代码在我这里完美运行。你使用的是哪个版本的PowerShell和Windows? - Tom
我正在使用:主要版本 次要版本 构建版本 修订版本
2 0 -1 -1
- Eric Vasilik
5个回答

1

您可能需要重新考虑使用第三方库。但是,如果您必须使用copyhere,请尝试以下方法:

new-item -type File test.zip -force
$zip = ( get-item test.zip ).fullname
$app = new-object -com shell.application
$folder = $app.namespace( $zip )
$item = new-item file.txt -itemtype file -value "Mooo" -force
$folder.copyhere( $item.fullname)
while($folder.Items().Item($item.Name) -Eq $null)
{
    start-sleep -seconds 0.01
    write-host "." -nonewline
}
dir test.zip # <---- Empty test.zip file
Get-Content -Encoding byte $zip 

如果必须使用 shell 来创建 zip 文件,那么这个解决方案可以很好地确定异步 copyhere 何时完成。但我仍然不确定这种方法是否会导致 zip 文件的部分写入。 - Eric Vasilik

1
我也遇到过这个问题,你需要做的就是等待压缩操作完成。因此,我想出了这个解决方案,你应该在执行"$folder.copyhere"或"Copy-ToZip" Powerpack cmdlet后放置此代码。
    $isCompleted = $false
    $guid = [Guid]::NewGuid().ToString()
    $tmpFileName = $zipFileName + $guid
    # The main idea is to try to rename target ZIP file. If it success then archiving operation is complete.
    while(!$isCompleted)
    {
        start-sleep -seconds 1
        Rename-Item $zipFileName $tmpFileName -ea 0 #Try to rename with suppressing errors
        if (Test-Path $tmpFileName)
        {
            Rename-Item $tmpFileName $zipFileName #Rename it back
            $isCompleted = $true
        }
    }

0
尝试像这样创建空的zip文件:
$zipfilename = "myzip.zip"
set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))

然后是你的代码的其余部分。

我盒子里的这段代码可以工作:

$zipfilename = "a.zip"
set-content $zipfilename ("PK" + [char]5 + [char]6 + ("$([char]0)" * 18))
$app = new-object -com shell.application
$zip = ( get-item a.zip ).fullname
$folder = $app.namespace( $zip )
$item = new-item file.txt -itemtype file -value "Mooo" -force
$folder.copyhere( $item.fullname )

要获取 zip 文件的内容,请使用以下代码:

$zipfilename = "myzip.zip"
$shellApplication = new-object -com shell.application
$zipPackage = $shellApplication.NameSpace($zipfilename)
$zipPackage.Items() | Select Path

如果你运行我的脚本两次,第二次运行时test.zip文件已经存在了,但结果是一样的 - 它仍然是空的。尽管如此,我还是尝试了这个,结果还是一样的 :-( - Eric Vasilik
在我的电脑上(XP Pro / PowerShell 2.0)可以运行以下操作:创建一个myfile.zip文件并添加一个file.txt文件。 - CB.
我觉得你误解了我的意思。我不想在创建zip文件后获得未压缩内容。我想要在创建zip文件的同一脚本中立即获得实际的zip文件(已压缩)。如果你将两个脚本合并为一个(稍作修改以更正zip文件名),结果是相同的——一个空的zip文件。 - Eric Vasilik
我重复一遍:在我的盒子里,脚本会创建包含file.txt文件的zip文件。不知道为什么你做不到。 - CB.

0
在闭包中创建文件,这样变量就会超出范围,PowerShell 就会关闭文件... 如果将该部分制作成子例程,则在返回时它会自然关闭。
new-item -type File test.zip -force
{ 
  $zip = ( get-item test.zip ).fullname
  $app = new-object -com shell.application
  $folder = $app.namespace( $zip )
  $item = new-item file.txt -itemtype file -value "Mooo" -force
  $folder.copyhere( $item.fullname )
}
dir test.zip # <---- Empty test.zip file
Get-Content -Encoding byte $zip

我尝试过这个,但是创建闭包或将代码放入函数中并没有改善情况。 - Eric Vasilik

0

这种压缩文件的方法不适用于自动化脚本。在 Windows 2003 和 Windows XP Server 上有 3GB 的限制。此外,它也不能提供正确的错误信息。


在折腾了一会儿之后,我不得不同意。调用shell来操作zip需要很多开销,并且非常间接。我看了一下@Christian提到的Inoic.zip库,发现它非常适合我的使用场景,可以创建zip文件字节而无需写入文件系统。我感谢每一个人提供的创造性解决方案! - Eric Vasilik

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接