Hi,
The application I am currently working on is a Silverlight OOB application (say, Application A) which generates Silverlight applications (say, Application B) dynamically. I have been using Infragistics compression library to create the XAP file dynamically.
Here is a glimpse of the structure. The resulting XAP file (XAP file for Application B) is carried around in the hosting Silverlight OOB application (Application A). The assets that go into the new XAP file (Application B) are in the user's MyDocuments folder. I have been able to use Infragistics Compression Libraray to extract the new XAP file and add the assets from user's MyDocuments folder and then produce the resultant XAP file. This process works fine.
The problem arises when large (~300MB) asset files are encountered which need to go into the output XAP file. With a couple of these files the resultant XAP file quickly becomes around 1GB. I am using byte array to compile the ZipFile.
Am I right in saying that it is not possible to give a combination of stream input and byte array input to the ZipFile?
Is there an effective way to manage and build large ZIP files using ZipFile and ZipEntry?
-Nrupal
I am not sure if I am understanding your question right, but you wish to add some items into the ZipFile using both streams and byte[]? Have you used the static method overloads on ZipEntry.CreateFile()? Two of those overloads take file name, location in archive, and then either a stream or byte[].
You can then add the result of ZipEntry.CreateFile to add into you ZipFile's .Entries property.
Thanks,
Rich
Hi Rich,
First to answer your question, Yes I have tried different overloads of the static methods on ZipEntry.
To put it in simple words, I would like to add large files to an existing zip archive. since we are dealing with large files, I would like it to be through streams, hoping that ZipFile.Save(...) is handling the logic to zip files piece by piece rather than taking up a whole lot of memory.
When I use Stream in the constructor for ZipFile, the output zip file is corrupt and it doesn't work. I have come across in another post that it is best to use the byteArray overloads. But using ByteArray would mean to hold all the files required to compress in memory. which is not a good idea to do so in my case where there are large files.
Konstontin Koynov from Infragistics says in another post on this forum,
"This basically means that if you have instatiated your ZipFile using the constructor which takes a stream and/or try to add an ZipEntry which is created by a stream Save operation wont be successful."
the link to the above post is http://community.infragistics.com/forums/t/51342.aspx
Now I am confused as to the use of Stream overloads. Can you please provide with a sample snippet that is capable of compressing large files and uses streams?
Thank you
Nrupal
There is no problem using stream to load a zip file or create an entry as long as the used streams remain open long enough. This means that if you load a zip file through a stream you need to keep the stream open until you finish your work with the zip file and it is no longer needed. The same applies to entries created through a stream.
My statement that you quoted above is not true in general. It was part of investigating an issue. Sorry for the confusion created.
I have attached a sample solution that demonstrates how to use streams with the Compression library.
Please let me know if you have any further issues.
Regards,
Yes, Konstantin is correct, here is another sample... the important thing is perventing the file streams from being disposed until the zip file has been saved. Using this sample I have create a new zip file w/ a 250mb, another 250mb, and a 600mb entry, resulting in a final zip of over 1gb.
<UserControl x:Class="CompressionTest.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400"> <Grid x:Name="LayoutRoot" Background="White"> <StackPanel> <Button x:Name="loadZip" Click="loadZip_Click" Content="Load a zip" /> <Button x:Name="createZip" Click="createZip_Click" Content="Create a zip" /> <Button x:Name="insertNewEntry" Click="insertNewEntry_Click" Content="Insert new entry" /> <Button x:Name="saveZip" Click="saveZip_Click" Content="Save archive" /> </StackPanel> </Grid> </UserControl>
public partial class MainPage : UserControl { ZipFile zip; FileStream _origZip; List<FileStream> _openFiles; Stream _saveZip; public MainPage() { InitializeComponent(); _openFiles = new List<FileStream>(); } private void loadZip_Click(object sender, RoutedEventArgs e) { var openDlg = new OpenFileDialog(); openDlg.ShowDialog(); _origZip = openDlg.File.OpenRead(); zip = new ZipFile(_origZip); } private void insertNewEntry_Click(object sender, RoutedEventArgs e) { var openDlg = new OpenFileDialog(); openDlg.ShowDialog(); var openFile = openDlg.File.OpenRead(); zip.Entries.Add(ZipEntry.CreateFile(openDlg.File.Name, "/", openFile)); _openFiles.Add(openFile); } private void saveZip_Click(object sender, RoutedEventArgs e) { var saveDlg = new SaveFileDialog(); saveDlg.ShowDialog(); _saveZip = saveDlg.OpenFile(); zip.Save(_saveZip); if (_origZip != null) _origZip.Close(); foreach (var file in _openFiles) file.Close(); _openFiles.Clear(); _saveZip.Close(); } private void createZip_Click(object sender, RoutedEventArgs e) { zip = new ZipFile(); } }
Thanks guys, that really helped. I was doing something similar to creating a list of open streams and closing them after the save operation. The underlying stream was causing error, I was using ADODB.Stream object (COM interop).
thank for your sharing, it's really healpfull