Noman Amir
Noman Amir

Reputation: 963

Trouble compressing large files using vbs

I have jumbled up a vbs script to compress files older than 7 days using 7za's command line utility. While most of the logic works fine, I am able to compress single file into single zip file.

The problem arises when I try to add all matching files to one zip file. Below is the code snippet:

strCommand = "7za.exe -mx=9 a " & ObjectFolder & sysDate & ".zip " & strFileName
strRun = objShell.Run(strCommand, 0, True)

Now as per the 2nd line, setting True would make sure the script will wait till command is finished executing. But the problem is 7za is exiting immediately and going to the next loop, processing the next file and since it tries to create same zip file, I get access denied error.

Can someone please help me to fix this?

I have also tested the scenario in command prompt. What I did was, execute below 2 commands simultaneously in separate prompts:

Prompt 1: C:\7za.exe -mx=9 a test.zip c:\sample1.pdf

Prompt 2: C:\7za.exe -mx=9 a test.zip c:\sample2.pdf

Prompt 2 resulted in following error:

Error: test.zip is not supported archive

System error:
The process cannot access the file because it is being used by another process.

This is the same error I am getting in my script and I need help in resolving this. Any pointers will be helpful!

UPDATE:

With the great pointers provided by both John and Ansgar, I was able to resolve this! It turned out to be a bug in my script! In my script, I included a check to see if the file is in use by any other process before processing it for archive. So I was checking this by opening the file for appending using:

Set f = objFSO.OpenTextFile(strFile, ForAppending, True)

But before proceeding to process the same file, I was not CLOSING it in the script, hence the error: The process cannot access the file because it is being used by another process

After I closed the file, all went well!

Thanks Again for all the great support I got here!

As a token of gratitude, I am sharing the whole script for anyone's use. Please note that I am not the original author of this, I gathered it from various sources and tweaked it a little bit to suit my needs.

Archive.vbs

Const ForAppending = 8  ' Constant for file lock check

Dim objFSO, objFolder, objFiles, objShell
Dim file, fileExt, fileName, strCommand, strRun, strFile
Dim SFolder, OFolder, Extension, DaysOld, sDate

'''' SET THESE VARIABLES! ''''
SFolder = "C:\SourceFolder\"      'Folder to look in
OFolder = "C:\OutputFolder\"      'Folder to put archives in
Extension = "pdf"        'Extension of files you want to zip
DaysOld = 1        'Zip files older than this many days
''''''''''''''''''''''''''''''

sDate = DatePart("yyyy",Date) & "-" & Right("0" & DatePart("m",Date), 2) & "-" & Right("0" & DatePart("d",Date), 2)


'Create object for playing with files
Set objFSO = CreateObject("Scripting.FileSystemObject")

'Create shell object for running commands
Set objShell = wscript.createObject("wscript.shell")

'Set folder to look in
Set objFolder = objFSO.GetFolder(SFolder)

'Get files in folder
Set objFiles = objFolder.Files

'Loop through the files
For Each file in objFiles
  fileName = Split(file.Name, ".")
  fileExt = fileName(UBound(fileName))
  'See if it is the type of file we are looking for
  If fileExt = Extension Then
    'See if the file is older than the days chosen above
    If DateDiff("d", file.DateLastModified, Now()) >= DaysOld Then
      strFile = file.Path
      'See if the file is available or in use
        Set f = objFSO.OpenTextFile(strFile, ForAppending, True)
        If Err.Number = 70 Then ' i.e. if file is locked

        Else
        f.close
        strFName = objFSO.GetBaseName(file.name)
        strCommand = "C:\7za.exe -mx=9 a " & OFolder & sDate & ".zip " & strFile

        strRun = objShell.Run(strCommand, 0, True)
        'wscript.echo strCommand  ' un-comment this to check the file(s) being processed
        'file.Delete  ' un-comment this to delete the files after compressing.
        End If
    End If

  End If
Next

'Cleanup
Set objFiles = Nothing
Set objFolder = Nothing
Set objFSO = Nothing
Set objShell = Nothing
wscript.Quit

===========================

Thanks

-Noman A.

Upvotes: 0

Views: 1109

Answers (2)

Ansgar Wiechers
Ansgar Wiechers

Reputation: 200493

Your command shouldn't return before 7za has finished its task (and it doesn't in my tests). Try changing your code to the following, so you can see what's going on:

strCommand = "7za.exe -mx=9 a " & ObjectFolder & sysDate & ".zip " & strFileName
strCommand = "%COMSPEC% /k " & strCommand
strRun = objShell.Run(strCommand, 1, True)

It may also be a good idea to quote the filenames:

Function qq(str)
  qq = Chr(34) & str & Chr(34)
End Function

strCommand = "7za.exe -mx=9 a " & qq(ObjectFolder & sysDate & ".zip") & " " _
  & qq(strFileName)

Upvotes: 1

JohnLBevan
JohnLBevan

Reputation: 24470

Not quite what you asked for, but here's a batch script I use for a similar task in case that helps get you past of your immediate issue:

ArchiveScriptLog.Bat

::ensure we're in the right directory, then run the script & log the output
cls
pushd "c:\backup scripts"
ArchiveScript.bat > ArchiveScript.log
popd

ArchiveScript.bat

::Paths (must include the \ on the end).  There must be no space between the equals and the value
::UNC paths are acceptable

Set FolderToBackup=F:\EnterpriseArchitect\Energy\
Set BackupPath=F:\EnterpriseArchitect\!ARCHIVE\
Set RemoteBackupPath=\\ukccojdep01wok\h$\Energy\cciobis01edc\
Set SevenZip=C:\Program Files (x86)\7-Zip\

::Get DATE in yyyymmdd format; done in two lines to make it easy to change the date format
FOR /F "TOKENS=2,3,4 DELIMS=/ " %%A IN ('echo %Date%') DO (SET mm=%%A&SET dd=%%B&SET yyyy=%%C)
SET strDate=%yyyy%%mm%%dd%

::Set the Backup File to be the backup path with the current date & .zip on the end
Set BackupFile=%BackupPath%%strDate%.zip

::create a zip containing the contents of folderToBackup
pushd %SevenZip%
7z a "%BackupFile%" "%FolderToBackup%"
popd

::go to the archive directory & copy all files in there to the remote location (this accounts for previous errors if the network were unavailable)
pushd "%BackupPath%"
move *.zip "%RemoteBackupPath%"
popd

::delete off backups in the remote location which are older than 90 days
pushd "%RemoteBackupPath%"
forfiles /D -90 /M *.zip /C "cmd /c del @file"
popd

Upvotes: 1

Related Questions