压缩zip存档本身以外的文件夹中的所有文件

时间:2017-02-22 15:23:51

标签: windows vba excel-vba zip directory

我正在使用此代码将文件夹中的所有文件压缩到新创建的df.saveAsBigQueryTable("my-project:my_dataset.my_table") 文件中:

.zip

只要我的目标文件夹与我的文件的文件夹不同,就可以正常运行

但是当我尝试从文件夹中获取所有文件时,我遇到问题,将它们放入Dim FileNameZip, FolderName Dim filename As String, DefPath As String Dim oApp As Object (defining all paths needed) 'Create empty Zip File NewZip (FileNameZip) Set oApp = CreateObject("Shell.Application") 'Copy the files to the compressed folder oApp.Namespace(FileNameZip).CopyHere oApp.Namespace(FolderName).items 'Keep script waiting until Compressing is done On Error Resume Next Do Until oApp.Namespace(FileNameZip).items.Count = oApp.Namespace(FolderName).items.Count Application.Wait (Now + TimeValue("0:00:01")) Loop 并生成存档相同的文件夹 - 它会创建存档,然后尝试将其放入自身,这当然会失败。

我正在寻找一种方法来压缩文件夹中的所有文件,除了新创建的文件。

我在这里查看:https://msdn.microsoft.com/en-us/library/office/ff869597.aspx但这看起来非常特定于Outlook,我不知道如何将其应用到Windows文件夹。

3 个答案:

答案 0 :(得分:6)

不是一次添加所有文件(包括您创建的zip文件),而是使用FileSystemObject遍历文件,并在添加到zip之前将其名称与zip文件名进行比较:

Sub AddFilesToZip()

Dim fso As Object, zipFile As Object, objShell As Object
Dim fsoFolder As Object, fsoFile As Object
Dim timerStart As Single
Dim folderPath As String, zipName As String

folderPath = "C:\Users\darre\Desktop\New folder\" ' folder to zip
zipName = "myzipfile.zip" ' name of the zip file

Set fso = CreateObject("Scripting.FileSystemObject") ' create an fso to loop through the files

Set zipFile = fso.CreateTextFile(folderPath & zipName) ' create the zip file
zipFile.WriteLine Chr(80) & Chr(75) & Chr(5) & Chr(6) & String(18, 0)
zipFile.Close

Set objShell = CreateObject("Shell.Application")
Set fsoFolder = fso.GetFolder(folderPath)

For Each fsoFile In fsoFolder.Files ' loop through the files...

    Debug.Print fsoFile.name
    If fsoFile.name <> zipName Then ' and check it's not the zip file before adding them

        objShell.Namespace("" & folderPath & zipName).CopyHere fsoFile.Path

        timerStart = Timer
        Do While Timer < timerStart + 2
            Application.StatusBar = "Zipping, please wait..."
            DoEvents
        Loop

    End If

Next

' clean up
Application.StatusBar = ""
Set fsoFile = Nothing
Set fsoFolder = Nothing
Set objShell = Nothing
Set zipFile = Nothing
Set fso = Nothing

MsgBox "Zipped", vbInformation

End Sub

答案 1 :(得分:5)

我会在临时文件夹中创建zip文件,最后将其移动到目标文件夹。值得一提的两个注意事项:

1-循环方法直到项目计数在文件夹中相同且zip文件存在风险,因为如果单个项目的压缩失败,则会导致无限循环。因此,只要zip文件被shell锁定,就最好循环。

2-我将使用Shell的早期绑定,因为后期绑定Shell32.Application似乎在某些安装上存在问题。添加对Microsoft Shell Controls and Automation

的引用
Sub compressFolder(folderToCompress As String, targetZip As String)
    If Len(Dir(targetZip)) > 0 Then Kill targetZip

    ' Create a temporary zip file in the temp folder
    Dim tempZip As String: tempZip = Environ$("temp") & "\" & "tempzip1234.zip"
   CreateObject("Scripting.FileSystemObject").CreateTextFile(tempZip, True).Write _
        Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)

    ' compress the folder into the temporary zip file
    With New Shell ' For late binding: With CreateObject("Shell32.Application")
        .Namespace(tempZip).CopyHere .Namespace(folderToCompress).Items
    End With

    ' Move the temp zip to target. Loop until the move succeeds. It won't
    ' succeed until the zip completes because zip file is locked by the shell
    On Error Resume Next
    Do Until Len(Dir(targetZip)) > 0
        Application.Wait Now + TimeSerial(0, 0, 1)
        Name tempZip As targetZip
    Loop
End Sub

Sub someTest()
   compressFolder "C:\SO\SOZip", "C:\SO\SOZip\Test.zip"
End Sub

答案 2 :(得分:0)

我发现在没有第三方工具的情况下通过VBA进行压缩很难控制,下面可能不是直接的答案,但可能有助于解决问题。下面是我用来生成epub的代码的摘录,这些代码不仅仅是具有不同扩展名的zip文件。这个压缩部分在数百次运行中从未失败。

Public Function Zip_Create(ByVal StrFilePath As String) As Boolean
Dim FSO         As New FileSystemObject
Dim LngCounter  As Long

If Not FSO.FileExists(StrFilePath) Then
    'This makes the zip file, note the FilePath also caused issues
    'it should be a local file, suggest root of a drive and then use FSO
    'to open it
    LngCounter = FreeFile
    Open StrFilePath For Output As #LngCounter
    Print #LngCounter, "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
    Close #LngCounter
End If

Zip_Create = True

End Function

Public Function Zip_Insert(ByVal StrZipFilePath As String, ByVal StrObject As String) As Boolean
Dim BlnYesNo            As Boolean
Dim LngCounter          As Long
Dim LngCounter2         As Long
Dim ObjApp              As Object
Dim ObjFldrItm          As Object
Dim ObjFldrItms         As Object
Dim StrContainer        As String
Dim StrContainer2       As String

If Procs.Global_IsAPC Then

    'Create the zip if needed
    If Not FSA.File_Exists(StrZipFilePath) Then
        If Not Zip_Create(StrZipFilePath) Then
            Exit Function
        End If
    End If

    'Connect to the OS Shell
    Set ObjApp = CreateObject("Shell.Application")

        'Pause, if it has just been created the next piece of
        'code may not see it yet
        LngCounter2 = Round(Timer) + 1
        Do Until CLng(Timer) > LngCounter2
            DoEvents
        Loop

        'Divide the path and file
        StrContainer = Right(StrObject, Len(StrObject) - InStrRev(StrObject, "\"))
        StrObject = Left(StrObject, Len(StrObject) - Len(StrContainer))

        'Connect to the file (via the path)
        Set ObjFldrItm = ObjApp.NameSpace(CVar(StrObject)).Items.Item(CVar(StrContainer))

            'Pauses needed to avoid all crashes
            LngCounter2 = CLng(Timer) + 1
            Do Until CLng(Timer) > LngCounter2
                DoEvents
            Loop

            'If it is a folder then check there are items to copy (so as to not cause and error message
            BlnYesNo = True
            If ObjFldrItm.IsFolder Then
                If ObjFldrItm.GetFolder.Items.Count = 0 Then BlnYesNo = False
            End If

            If BlnYesNo Then

                'Take note of how many items are in the Zip file

                'Place item into the Zip file
                ObjApp.NameSpace(CVar(StrZipFilePath)).CopyHere ObjFldrItm

                'Pause to stop crashes
                LngCounter2 = CLng(Timer) + 1
                Do Until CLng(Timer) > LngCounter2
                    DoEvents
                Loop

                'Be Happy
                Zip_Insert = True

            End If

        Set ObjFldrItm = Nothing

    Set ObjApp = Nothing
End If

End Function