1

I'd like to know if there is anyway of zipping files using vbscript without using WScript.Sleep. Following is my script(Utility methods are skipped);

Sub Main
   Dim Path
   Dim ZipFile
   Dim objShell

   ZipFile = WScript.Arguments(0)
   Path = WScript.Arguments(1)

   Dim a: a = ListDir(Path)
   If UBound(a) = -1 then
      WScript.Echo "No files found."
      Exit Sub
      End If

   CreateObject("Scripting.FileSystemObject").CreateTextFile(ZipFile, True).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
   Set objShell = CreateObject("Shell.Application")
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   Dim FileName
   For Each FileName In a
      WScript.Echo FileName
      objShell.NameSpace(fso.GetAbsolutePathName(ZipFile)).CopyHere(FileName)
      'Required!
      WScript.Sleep 4000
      Next
   End Sub

If you see the code, I'm using sleep command to wait for certain time(Assuming that the files gets zipped in the specified time). However, this is causing the script to wait for the same time even for the small files which is not good. I've searched online if there is anyway of zipping files synchronously, but couldn't get the answer.

geekprogrammer
  • 1,108
  • 1
  • 13
  • 39

2 Answers2

2

Shell.NameSpace operations are asynchronous. And as far as i know, from vbscript, it is not possible to completely remove the Sleep, as it is necessary to at least wait for the asynchonous process to start, BUT, you can try to get access to the zip file to know if the operation has ended. (sorry, i have rewritted your code for testing)

Option Explicit

Sub Main

    ' Retrieve arguments
    Dim strPath, strZipFile
    If Wscript.Arguments.UnNamed.Count < 2 Then 
        WScript.Echo "No arguments"
        Exit Sub
    End If
    strZipFile = WScript.Arguments(0)
    strPath = WScript.Arguments(1)

    ' Create needed objects
    Dim fso, shell
    Set fso   = WScript.CreateObject("Scripting.FileSystemObject")
    Set shell = WScript.CreateObject("Shell.Application")

    ' Check for valid source path
    If Not fso.FolderExists( strPath ) Then 
        WScript.Echo "Folder does not exist"
        Exit Sub
    End If
    Dim oFolder
    Set oFolder = fso.GetFolder( strPath )
    If oFolder.Files.Count < 1 Then 
        WScript.Echo "No files found"
        Exit Sub
    End If

    ' Initialize zip file access
    Dim oZipFile
    strZipFile = fso.GetAbsolutePathName( strZipFile )
    fso.CreateTextFile( strZipFile, True ).Write "PK" & Chr(5) & Chr(6) & String(18, vbNullChar)
    Set oZipFile = shell.NameSpace( strZipFile )

    ' Add files to zip
    Dim oFile
    For Each oFile In oFolder.Files
        WScript.Echo oFile.Name
        oZipFile.CopyHere(oFile.Path)
        WScript.Sleep 500
        WaitForFile strZipFile, -1
    Next

End Sub

' Wait for a file to become writeable

Function WaitForFile( FullPathToFile, TimeToWait )
Dim fso, timeLimit, oFile

    WaitForFile = False
    Set fso = WScript.CreateObject("Scripting.FileSystemObject")

    ' Determine if we are going to wait for the file
    If TimeToWait > 0 Then 
        timeLimit = DateAdd("s", TimeToWait, Now )
    ElseIf TimeToWait = 0 Then
        timeLimit = Now
    Else 
        timeLimit = DateAdd("yyyy", 100, Now)
    End If

    ' Loop until the file can be written or the timeout has been reached
    On Error Resume Next
    Do
        Err.Clear
        Set oFile = fso.OpenTextFile( FullPathToFile, 8, False )
        If Err.Number = 0 Then
            oFile.Close
            WaitForFile = True
            Exit Do
        End If
        WScript.Sleep 100
    Loop While Now < timeLimit
    On Error GoTo 0

End Function

' Call main process
    Main

The WaitForFile function will return a Boolean indicating if the file has become writeable (there is no operation locking the file) in the indicated timeout. Sample code uses -1 as timeout, that is, wait until the file is writeable. When the NameSpace operation has ended (the source file has been zipped), there will be no locks in the zip file and the function will return.

MC ND
  • 69,615
  • 8
  • 84
  • 126
  • It's not sufficient to just wait for the operation to start. When the script terminates, the `Shell.Application` object is terminated with it, thus ending any operation it might still be carrying out. – Ansgar Wiechers Jul 24 '14 at 17:05
  • @AnsgarWiechers, no. Maybe i didn't explain it well. What has been removed is the fixed delay for the `CopyHere` operation. Now, the process waits to let the operation start and then wait until the copy operation releases the lock on the zip file. The `Shell.Application` object is not released until all the copy operations are handled. That way the process only waits the required time. – MC ND Jul 24 '14 at 19:04
0

Seems to me you could replace the current sleep with a loop comparing file count in the ZipFile with file count in the source folder. If one is smaller than the other, do a short sleep. To make it work, you'll need to modify a to be an FSO folder object instead of an array of file names. Then you can use the .Count property of it. Like This.

Community
  • 1
  • 1
msumbufu
  • 21
  • 4