Windows 的内置 ZIP 压缩可以编写脚本吗?

Posted

技术标签:

【中文标题】Windows 的内置 ZIP 压缩可以编写脚本吗?【英文标题】:Can Windows' built-in ZIP compression be scripted? 【发布时间】:2010-09-07 00:14:44 【问题描述】:

Windows XP/Vista/2003/2008 中内置的 ZIP 压缩是否完全可以编写脚本?我必须从 BAT/CMD 文件调用什么可执行文件?还是可以用VBScript来做?

我意识到使用WinZip、7-Zip 和其他外部应用程序可以做到这一点,但我正在寻找不需要安装外部应用程序的东西。

【问题讨论】:

Google 上有各种 VBScript 实现,例如“Zip and UnZip Files Using the Windows Shell (XP, Vista, 2003 and 2008) and VBScript”。我没有测试过这些,但很可能它们只是“压缩”,而不是压缩。 您对 zip 和 compress 的区别是什么? 您可以在不压缩的情况下将文件“压缩”到单个文件中,就像 unix 中的“tar”。这允许您将文件作为一个包分发,但不会减少它们的磁盘空间大小。 它们很可能只是“压缩”,而不是压缩。不,这是不对的。那里的脚本会创建一个 zip 文件,并压缩条目。 【参考方案1】:

也有使用内置压缩窗口的zip 和unzip 的VBA 方法,这应该可以让您了解系统的运行方式。您可以将这些方法构建到您选择的脚本语言中。

基本原则是在windows中你可以把一个zip文件当成一个目录,然后复制进去和复制出来。因此,要创建一个新的 zip 文件,您只需创建一个扩展名为 .zip 的文件,该文件具有空 zip 文件的正确标题。然后你关闭它,并告诉windows你想把文件复制到它,就好像它是另一个目录一样。

解压缩更容易 - 只需将其视为目录即可。

万一网页再次丢失,下面是一些相关代码sn-ps:

邮编

Sub NewZip(sPath)
'Create empty Zip File
'Changed by keepITcool Dec-12-2005
    If Len(Dir(sPath)) > 0 Then Kill sPath
    Open sPath For Output As #1
    Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
    Close #1
End Sub


Function bIsBookOpen(ByRef szBookName As String) As Boolean
' Rob Bovey
    On Error Resume Next
    bIsBookOpen = Not (Application.Workbooks(szBookName) Is Nothing)
End Function


Function Split97(sStr As Variant, sdelim As String) As Variant
'Tom Ogilvy
    Split97 = Evaluate("""" & _
                       Application.Substitute(sStr, sdelim, """,""") & """")
End Function

Sub Zip_File_Or_Files()
    Dim strDate As String, DefPath As String, sFName As String
    Dim oApp As Object, iCtr As Long, I As Integer
    Dim FName, vArr, FileNameZip

    DefPath = Application.DefaultFilePath
    If Right(DefPath, 1) <> "\" Then
        DefPath = DefPath & "\"
    End If

    strDate = Format(Now, " dd-mmm-yy h-mm-ss")
    FileNameZip = DefPath & "MyFilesZip " & strDate & ".zip"

    'Browse to the file(s), use the Ctrl key to select more files
    FName = Application.GetOpenFilename(filefilter:="Excel Files (*.xl*), *.xl*", _
                    MultiSelect:=True, Title:="Select the files you want to zip")
    If IsArray(FName) = False Then
        'do nothing
    Else
        'Create empty Zip File
        NewZip (FileNameZip)
        Set oApp = CreateObject("Shell.Application")
        I = 0
        For iCtr = LBound(FName) To UBound(FName)
            vArr = Split97(FName(iCtr), "\")
            sFName = vArr(UBound(vArr))
            If bIsBookOpen(sFName) Then
                MsgBox "You can't zip a file that is open!" & vbLf & _
                       "Please close it and try again: " & FName(iCtr)
            Else
                'Copy the file to the compressed folder
                I = I + 1
                oApp.Namespace(FileNameZip).CopyHere FName(iCtr)

                'Keep script waiting until Compressing is done
                On Error Resume Next
                Do Until oApp.Namespace(FileNameZip).items.Count = I
                    Application.Wait (Now + TimeValue("0:00:01"))
                Loop
                On Error GoTo 0
            End If
        Next iCtr

        MsgBox "You find the zipfile here: " & FileNameZip
    End If
End Sub

解压缩

Sub Unzip1()
    Dim FSO As Object
    Dim oApp As Object
    Dim Fname As Variant
    Dim FileNameFolder As Variant
    Dim DefPath As String
    Dim strDate As String

    Fname = Application.GetOpenFilename(filefilter:="Zip Files (*.zip), *.zip", _
                                        MultiSelect:=False)
    If Fname = False Then
        'Do nothing
    Else
        'Root folder for the new folder.
        'You can also use DefPath = "C:\Users\Ron\test\"
        DefPath = Application.DefaultFilePath
        If Right(DefPath, 1) <> "\" Then
            DefPath = DefPath & "\"
        End If

        'Create the folder name
        strDate = Format(Now, " dd-mm-yy h-mm-ss")
        FileNameFolder = DefPath & "MyUnzipFolder " & strDate & "\"

        'Make the normal folder in DefPath
        MkDir FileNameFolder

        'Extract the files into the newly created folder
        Set oApp = CreateObject("Shell.Application")

        oApp.Namespace(FileNameFolder).CopyHere oApp.Namespace(Fname).items

        'If you want to extract only one file you can use this:
        'oApp.Namespace(FileNameFolder).CopyHere _
         'oApp.Namespace(Fname).items.Item("test.txt")

        MsgBox "You find the files here: " & FileNameFolder

        On Error Resume Next
        Set FSO = CreateObject("scripting.filesystemobject")
        FSO.deletefolder Environ("Temp") & "\Temporary Directory*", True
    End If
End Sub

【讨论】:

警告:发布的脚本依赖于 Windows shell 的实现依赖行为,例如,当第三方压缩软件更改 ZIP 存档的默认 OLE 动词时,很容易中断。此外,zipfldr.dll COM 对象记录或支持 MS 用于此用途。 zip 文件上的虚假 OLE 动词不会干扰上述提供的脚本。不支持(或记录)它并不自动意味着 MS 会破坏它。他们可能会,但他们也可能会记录下来。 请阅读这里,windows shell zipping 有 2GB 的限制:naterice.com/blog/template_permalink.asp?id=64 请注意,带有外语字符的文件夹和文件名可能无法使用此方法进行压缩,即使 7z 等实用程序可以使用它们生成 zip 文件。这是 Windows 压缩文件夹的限制。【参考方案2】:

是的,这可以使用 VBScript 编写脚本。例如,以下代码可以从目录创建 zip:

Dim fso, winShell, MyTarget, MySource, file
Set fso = CreateObject("Scripting.FileSystemObject")
Set winShell = createObject("shell.application")


MyTarget = Wscript.Arguments.Item(0)
MySource = Wscript.Arguments.Item(1)

Wscript.Echo "Adding " & MySource & " to " & MyTarget

'create a new clean zip archive
Set file = fso.CreateTextFile(MyTarget, True)
file.write("PK" & chr(5) & chr(6) & string(18,chr(0)))
file.close

winShell.NameSpace(MyTarget).CopyHere winShell.NameSpace(MySource).Items

do until winShell.namespace(MyTarget).items.count = winShell.namespace(MySource).items.count
    wscript.sleep 1000 
loop

Set winShell = Nothing
Set fso = Nothing

您可能还会发现 http://www.naterice.com/blog/template_permalink.asp?id=64 很有帮助,因为它在 VBScript 中包含完整的 Unzip/Zip 实现。

如果您每 500 毫秒检查一次大小而不是项目计数,则它对大文件更有效。 Win 7 会立即写入文件,尽管它没有完成压缩:

set fso=createobject("scripting.filesystemobject")
Set h=fso.getFile(DestZip)
do
    wscript.sleep 500
    max = h.size
loop while h.size > max 

非常适合处理大量日志文件。

【讨论】:

这在 Vista 上有效吗?我遇到了一些问题,并且准备声称 Vista 是罪魁祸首。【参考方案3】:

为了清楚起见:GZip 并不是 Guy Starbuck 在 8 月份的评论中建议的仅限 MS 的算法。 System.IO.Compression 中的 GZipStream 使用 Deflate 算法,与 zlib 库和许多其他 zip 工具相同。该类与 gzip 等 unix 实用程序完全可互操作。

GZipStream 类不能从命令行或 VBScript 编写脚本来生成 ZIP 文件,因此仅靠它不能回答原始发帖人的请求。

免费的DotNetZip 库可以读取和生成 zip 文件,并且可以从 VBScript 或 Powershell 编写脚本。它还包括用于生成和读取/提取 zip 文件的命令行工具。

下面是 VBScript 的一些代码:

dim filename 
filename = "C:\temp\ZipFile-created-from-VBScript.zip"

WScript.echo("Instantiating a ZipFile object...")
dim zip 
set zip = CreateObject("Ionic.Zip.ZipFile")

WScript.echo("using AES256 encryption...")
zip.Encryption = 3

WScript.echo("setting the password...")
zip.Password = "Very.Secret.Password!"

WScript.echo("adding a selection of files...")
zip.AddSelectedFiles("*.js")
zip.AddSelectedFiles("*.vbs")

WScript.echo("setting the save name...")
zip.Name = filename

WScript.echo("Saving...")
zip.Save()

WScript.echo("Disposing...")
zip.Dispose()

WScript.echo("Done.")

下面是一些 Powershell 的代码:

[System.Reflection.Assembly]::LoadFrom("c:\\dinoch\\bin\\Ionic.Zip.dll");

$directoryToZip = "c:\\temp";
$zipfile =  new-object Ionic.Zip.ZipFile;
$e= $zipfile.AddEntry("Readme.txt", "This is a zipfile created from within powershell.")
$e= $zipfile.AddDirectory($directoryToZip, "home")
$zipfile.Save("ZipFiles.ps1.out.zip");

在 .bat 或 .cmd 文件中,您可以使用 zipit.exe 或 unzip.exe 工具。例如:

zipit NewZip.zip  -s "This is string content for an entry"  Readme.txt  src 

【讨论】:

【参考方案4】:

在 SourceForge (http://sourceforge.net/projects/unxutils) 上的 UnxUtils 包中有 zip 和 unzip 可执行文件(以及大量其他有用的应用程序)。将它们复制到 PATH 中的某个位置,例如“c:\windows”,然后您就可以将它们包含在脚本中。

这不是完美的解决方案(或您要求的解决方案),而是一个体面的工作。

【讨论】:

UnxUtils 项目似乎不再被维护(自 2007 年以来没有什么新东西)。 GNUWin32 project 在 Windows 上有更新的 GNU 工具版本。它包括 InfoZip 的 zip/unzip 的构建。但是直接InfoZip buildfrom their own source会更好更安全。【参考方案5】:

要创建压缩存档,您可以使用实用程序 MAKECAB.EXE

【讨论】:

【参考方案6】:

这是我尝试总结压缩和解压缩的内置功能窗口 - How can I compress (/ zip ) and uncompress (/ unzip ) files and folders with batch file without using any external tools?

有一些给定的解决方案应该适用于几乎每台 Windows 机器。

关于 shell.application 和 WSH,我更喜欢 jscript 因为它允许使用不需要临时文件的混合批处理/jscript 文件(扩展名为 .bat)。我已将解压缩和压缩功能放在一个文件中以及更多功能。

【讨论】:

以上是关于Windows 的内置 ZIP 压缩可以编写脚本吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用 Windows 的内置功能从脚本中压缩或解压缩?

使用windows脚本编写自动压缩文件、删除源文件的脚本?

windows 压缩指定目录下每个目录和文件为zip文件的powershell脚本

windows 压缩指定目录下每个目录和文件为zip文件的powershell脚本

windows 压缩指定目录下每个目录和文件为zip文件的powershell脚本

可以将 7-zip 的标准输出提供给 PHP 脚本吗?