Zipping Up Code with ZipForge - ' Streaming Files ' (
Page 4 of 4 )
Streaming Files with ZipForge
At a basic level, ZipForge can be used to zip and unzip sets of files on the hard drive. But at a more sophisticated level, you can use to read data into a memory stream, making the data available for your program.
ADVERTISEMENT
Most applications need to read and write user files. Using persistent objects, you can easily write your data to a file, and then recreate your data when the file is opened. But with the help with a component such as ZipForge, you can represent your data as multiple files within a single zip archive file.
To demonstrate this concept, I wrote a simple function that saves user data to a single zip archive. The function saves a set of general metadata to one file within the zip archive. Next, the function saves the current user data to a new file within the archive, keeping all previous versions.
This could be useful if you're writing an application that needs to keep versions of previous files. I could think of many different reasons for this; for example, authors and editors often want several versions of a document available.
Here's the code, which I wrote in VB.NET:
Imports ComponentAce.Compression.ZipForge
Imports System.Collections.Generic
Module Module1
Structure UserDataInfo
Public UpdateDate As DateTime
Public Username As String
Public DataVersion As Int32
Public Sub WriteToStream(ByVal thestream As System.IO.Stream)
Dim writer As New System.IO.BinaryWriter(thestream)
writer.Write(UpdateDate.ToBinary)
writer.Write(Username)
writer.Write(DataVersion)
End Sub
Public Sub ReadFromStream(ByVal thestream As System.IO.Stream)
Dim reader As New System.IO.BinaryReader(thestream)
UpdateDate = DateTime.FromBinary(reader.ReadInt64)
Username = reader.ReadString
DataVersion = reader.ReadInt32
End Sub
End Structure
Sub SaveToZip(ByVal TheUsername As String, _
ByVal TheFile As String)
Dim datainfo As New UserDataInfo
datainfo.Username = TheUsername
datainfo.DataVersion = 1
Dim zip As New ZipForge
zip.FileName = TheFile
' If archive exists, get metadata
If System.IO.File.Exists(zip.FileName) Then
zip.OpenArchive(System.IO.FileMode.Open)
Dim archiveItem As _
ComponentAce.Compression.ZipForge.ArchiveItem = _
New ComponentAce.Compression.ZipForge.ArchiveItem()
If zip.FindFirst("info.dat", archiveItem) Then
Dim memstr As New System.IO.MemoryStream
zip.ExtractToStream("info.dat", memstr)
memstr.Seek(0, System.IO.SeekOrigin.Begin)
datainfo.ReadFromStream(memstr)
datainfo.DataVersion += 1
memstr.Close()
End If
zip.CloseArchive()
End If
' Save Options as one file in the archive
If System.IO.File.Exists(zip.FileName) Then
zip.OpenArchive(System.IO.FileMode.Open)
Else
zip.OpenArchive(System.IO.FileMode.Create)
End If
Dim outstr As New System.IO.MemoryStream
datainfo.WriteToStream(outstr)
zip.AddFromStream("info.dat", outstr)
outstr.Close()
' Save next version of user data as another file in archive
Dim dataname As String = "data\userdata" + _
datainfo.DataVersion.ToString + ".dat"
outstr = New System.IO.MemoryStream
Dim outdata As New System.IO.BinaryWriter(outstr)
' Just some sample application data...
outdata.Write(1)
outdata.Write(100)
outdata.Write("hello")
outdata.Write("test")
zip.AddFromStream(dataname, outstr)
outstr.Close()
zip.CloseArchive()
End Sub
Sub Main()
SaveToZip("jeff", "c:\userdata.zip")
End Sub
End Module
This sample code only saves data; it does not read it. And I made up some random data that it writes out. But it demonstrates the concept. The first time the program is run it creates the zip archive file, and places in the archive the metadata file called info.dat. Then it writes the data out to a file called data\userdata1.dat.
The next time the program is run, it opens the existing .zip file, and reads in the info.dat metadata. Using the power of the .NET streams, the metadata goes into a structure I created called UserDataInfo. This structure includes a version number, which is incremented.
The UserDataInfo is then streamed back into the info.dat file, which is then re-written into the zip file. Finally, a new data file is written with the updated version number, such as data\userdata2.dat.
Figure 1. The zip file now contains metadata and three versions of the data.
The figure shows what the zip file looks like after three runs of the sample program. (I opened the file in WinZip to look at it.) You can see three different versions of the user data is present, and that they exist in a subdirectory called data.
Tip: In the sample program, I gave my archive file a .zip extension. However, if this routine were used in a commercial application, I would likely use a custom extension so that the zip file could be associated with my program. The ZipForge class, after all, doesn't require that the archive files have a .zip extension.
A Compressed Conclusion
ZipForge also has some other nice features which I didn't mention. For examle, you can do transaction processing, wherein you add files to a zip file, and then ultimately commit the changes, or, if you need to, undo the changes before they're committed to file. (That's much like a database feature.) That can definitely be handy. The control also has events that you can respond to. For example, in a GUI application, you can display a progress bar that's incremented as the zipping or unzipping takes place.
But do you even need ZipForge? As I alluded to earlier, the .NET framework includes the System.IO.Compression namespace, which contains two classes for compressing data, DeflateStream, and GZipStream. Comparing these classes to ZipForge, however, is comparing apples and oranges. These two .NET classes provide compression within a stream, and they only provide a single algorithm. ZipForge, however, reads and writes compressed data stored in the ZIP file format, and can use many different compression algorithms.
Also, I found on Microsoft's MSDN.com website a discussion questioning the performance of these two built-in .NET classes, as well as concerns about intellectual property licensing. (It might not be a concern, but you would want to talk it over with an attorney to be sure.)
Still, the native .NET DeflateStream and GZipStream classes might be all you want or need, if you're compressing data and then storing the data into a single file. If, however, you're reading multiple files all compressed and stored in a single ZIP file, these classes won't be enough. That's where a library such as ZipForge comes in.
I definitely was impressed with ZipForge and I certainly recommend it.