My application will be storing large amounts of cached data to local storage for performance and disconnected purposes. I have tried to use SharpZipLib to compress the cache files that are created, but I'm having some difficulty.
I can get the file created, but it is invalid. Windows' built-in zip system and 7-zip both indicate that the file is invalid. When I attempt to open the file programmatically through SharpZipLib, I get the exception "Wrong Central Directory signature." I think part of the problem is that I'm creating the zip file directly from a MemoryStream, so there is no "root" directory. Not sure how to create one programmatically with SharpZipLib.
The EntityManager below is the IdeaBlade DevForce-generated "datacontext." It can save its contents to a stream for purposes of serializing to disk for caching.
Here's my code:
private void SaveCacheFile(string FileName, EntityManager em)
{
using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream isfs = new IsolatedStorageFileStream(FileName, System.IO.FileMode.CreateNew, isf))
{
MemoryStream inStream = new MemoryStream();
MemoryStream outStream = new MemoryStream();
Crc32 crc = new Crc32();
em.CacheStateManager.SaveCacheState(inStream, false, true);
inStream.Position = 0;
ZipOutputStream zipStream = new ZipOutputStream(outStream);
zipStream.IsStreamOwner = false;
zipStream.SetLevel(3);
ZipEntry newEntry = new ZipEntry(FileName);
byte[] buffer = new byte[inStream.Length];
inStream.Read(buffer, 0, buffer.Length);
newEntry.DateTime = DateTime.Now;
newEntry.Size = inStream.Length;
crc.Reset();
crc.Update(buffer);
newEntry.Crc = crc.Value;
zipStream.PutNextEntry(newEntry);
buffer = null;
outStream.Position = 0;
inStream.Position = 0;
StreamUtils.Copy(inStream, zipStream, new byte[4096]);
zipStream.CloseEntry();
zipStream.Finish();
zipStream.Close();
outStream.Position = 0;
StreamUtils.Copy(outStream, isfs, new byte[4096]);
outStream.Close();
}
}
}
Creating a zip file straight from memory is not your problem. SharpZipLib uses the parameter in the ZipEntry
constructor to determine the path, and does not care if that path has subdirectories or not.
using (ZipOutputStream zipStreamOut = new ZipOutputStream(outputstream))
{
zipStreamOut.PutNextEntry(new ZipEntry("arbitrary.ext"));
zipstreamOut.Write(mybytearraydata, 0, mybytearraydata.Length);
zipStreamOut.Finish();
//Line below needed if outputstream is a MemoryStream and you are
//passing it to a function expecting a stream.
outputstream.Position = 0;
//DoStuff. Optional; Not necessary if e.g., outputstream is a FileStream.
}