Would you be open to a different solution that doesn't use WinZip at all? The .Net runtime actually has compression built into it and recent versions have made it even easier to us to use.
For the code below to work you need to have .Net 4.5 and you need to add a reference to both System.IO.Compression
and System.IO.Compression.FileSystem
in your project. It walks a given folder, adds files to a zip file, and creates new zip files once a maximum byte threshold is reached. The only downside of this code is that the maximum byte threshold is calculated based on the uncompressed file length because the compressed size isn't known until later. However, based on your requirements this should be a problem.
The code's comments should hopefully explain everything. There are two methods, one takes an optional array of file extensions that you don't want to compress. To use the code to compress your desktop to a folder in your "My Documents" folder using a byte threshold of 50MB you'd just do something like:
Dim FolderToCompress = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
Dim FolderToSaveZipTo = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "ZIPs")
CompressFolder(FolderToCompress, FolderToSaveZipTo, "MyArchive", 1024 * 1024 * 50)
And here's the code:
''' <summary>
''' Compress a given folder splitting the zip files based on a supplied maximum uncompressed file length.
''' </summary>
''' <param name="folderToCompress">The folder to compress.</param>
''' <param name="folderToSaveZipFilesTo">The folder to save the compress files to.</param>
''' <param name="zipFileNameWithoutExtension">The file excluding the .zip extension to save to.</param>
''' <param name="maximumBytesToCompressPerFile">The maximum number of uncompress bytes that will be put into each zip file.</param>
''' <param name="fileExtensionsNotToCompress">An array of file extensions, including the leading period, to store only and not compress.</param>
Public Shared Sub CompressFolder(
folderToCompress As String,
folderToSaveZipFilesTo As String,
zipFileNameWithoutExtension As String,
maximumBytesToCompressPerFile As Long,
fileExtensionsNotToCompress() As String
)
''Create the directory if it doesn't exist already
Directory.CreateDirectory(folderToSaveZipFilesTo)
''Create a formattable string that increments an index each time
Dim FileNameFormatForZip = zipFileNameWithoutExtension & "_{0}.zip"
Dim CurrentZipFileIndex = 0
''The total amount of uncompressed files process so far
Dim CurrentUncompressedBytesProcessedSoFar As Long = 0
''Objects that we'll init below
Dim FileStreamForZip As Stream = Nothing
Dim Zip As ZipArchive = Nothing
''Loop through each file in the given directory including all child directories
For Each FI In Directory.EnumerateFiles(folderToCompress, "*.*", SearchOption.AllDirectories)
''Get the local file name relative to the parent directory
Dim LocalName = FI.Replace(folderToCompress, "").TrimStart("\"c)
''If we don't currently have a stream created, create one
If FileStreamForZip Is Nothing Then
Dim FileToSaveZipTo = Path.Combine(folderToSaveZipFilesTo, String.Format(FileNameFormatForZip, CurrentZipFileIndex))
FileStreamForZip = New FileStream(FileToSaveZipTo, FileMode.Create, FileAccess.Write, FileShare.None)
Zip = New ZipArchive(FileStreamForZip, ZipArchiveMode.Create)
End If
''Set a default compression level
Dim CompressionLevel = System.IO.Compression.CompressionLevel.Optimal
''However, if the current file extension is on our do not compress list then only set it to store
If fileExtensionsNotToCompress.Contains(New System.IO.FileInfo(FI).Extension) Then
CompressionLevel = Compression.CompressionLevel.NoCompression
End If
''Create our zip entry
Dim ZE = Zip.CreateEntry(LocalName, CompressionLevel)
''Add our file's contents to the entry
Using ZipStream = ZE.Open()
Using FileStream = File.Open(FI, FileMode.Open, FileAccess.Read, FileShare.Read)
FileStream.CopyTo(ZipStream)
End Using
End Using
''Increment our file byte counter by the uncompressed file's original size
''Unfortunately we can't use the ZE.CompressedLength because that is only available
''during the reading of a ZIP file
CurrentUncompressedBytesProcessedSoFar += New System.IO.FileInfo(FI).Length
''If we're over the threshold for maximum bytes
If CurrentUncompressedBytesProcessedSoFar >= maximumBytesToCompressPerFile Then
''Clean up and dispose of our objects
Zip.Dispose()
Zip = Nothing
FileStreamForZip.Dispose()
FileStreamForZip = Nothing
''Reset our counter
CurrentUncompressedBytesProcessedSoFar = 0
''Increment the current file index
CurrentZipFileIndex += 1
End If
Next
''Clean up
If Zip IsNot Nothing Then
Zip.Dispose()
Zip = Nothing
End If
If FileStreamForZip IsNot Nothing Then
FileStreamForZip.Dispose()
FileStreamForZip = Nothing
End If
End Sub
''' <summary>
''' Compress a given folder splitting the zip files based on a supplied maximum uncompressed file length.
''' </summary>
''' <param name="folderToCompress">The folder to compress.</param>
''' <param name="folderToSaveZipFilesTo">The folder to save the compress files to.</param>
''' <param name="zipFileNameWithoutExtension">The file excluding the .zip extension to save to.</param>
''' <param name="maximumBytesToCompressPerFile">The maximum number of uncompress bytes that will be put into each zip file.</param>
Public Shared Sub CompressFolder(folderToCompress As String, folderToSaveZipFilesTo As String, zipFileNameWithoutExtension As String, maximumBytesToCompressPerFile As Long )
CompressFolder(folderToCompress, folderToSaveZipFilesTo, zipFileNameWithoutExtension, maximumBytesToCompressPerFile, {".zip", ".mp4", ".wmv"})
End Sub