C# | Visual Basic | Visual C++ |
public ZipEntry AddEntry( string entryName, WriteDelegate writer )
Public Function AddEntry ( _ entryName As String, _ writer As WriteDelegate _ ) As ZipEntry
public: ZipEntry^ AddEntry( String^ entryName, WriteDelegate^ writer )
- entryName (String)
- the name of the entry to add
- writer (WriteDelegate)
- the delegate which will write the entry content
When the application needs to write the zip entry data, use this method to add the ZipEntry. For example, in the case that the application wishes to write the XML representation of a DataSet into a ZipEntry, the application can use this method to do so.
For ZipFile properties including Encryption, Password, SetCompression, ProvisionalAlternateEncoding, ExtractExistingFile, ZipErrorAction, and CompressionLevel, their respective values at the time of this call will be applied to the ZipEntry added.
About progress events: When using the WriteDelegate, DotNetZip does not issue any SaveProgress events with EventType = Saving_EntryBytesRead. (This is because it is the application's code that runs in WriteDelegate - there's no way for DotNetZip to know when to issue a EntryBytesRead event.) Applications that want to update a progress bar or similar status indicator should do so from within the WriteDelegate itself. DotNetZip will issue the other SaveProgress events, including Saving_Started, Saving_BeforeWriteEntry, and Saving_AfterWriteEntry.
Note: When you use PKZip encryption, it's normally necessary to compute the CRC of the content to be encrypted, before compressing or encrypting it. Therefore, when using PKZip encryption with a WriteDelegate, the WriteDelegate CAN BE called twice: once to compute the CRC, and the second time to potentially compress and encrypt. Surprising, but true. This is because PKWARE specified that the encryption initialization data depends on the CRC. If this happens, for each call of the delegate, your application must stream the same entry data in its entirety. If your application writes different data during the second call, it will result in a corrupt zip file.
The double-read behavior happens with all types of entries, not only those that use WriteDelegate. It happens if you add an entry from a filesystem file, or using a string, or a stream, or an opener/closer pair. But in those cases, DotNetZip takes care of reading twice; in the case of the WriteDelegate, the application code gets invoked twice. Be aware.
As you can imagine, this can cause performance problems for large streams, and it can lead to correctness problems when you use a WriteDelegate. This is a pretty big pitfall. There are two ways to avoid it. First, and most preferred: don't use PKZIP encryption. If you use the WinZip AES encryption, this problem doesn't occur, because the encryption protocol doesn't require the CRC up front. Second: if you do choose to use PKZIP encryption, write out to a non-seekable stream (like standard output, or the Response.OutputStream in an ASP.NET application). In this case, DotNetZip will use an alternative encryption protocol that does not rely on the CRC of the content. This also implies setting bit 3 in the zip entry, which still presents problems for some zip tools.
In the future I may modify DotNetZip to *always* use bit 3 when PKZIP encryption is in use. This seems like a win overall, but there will be some work involved. If you feel strongly about it, visit the DotNetZip forums and vote up the Workitem tracking this issue.
var c1= new System.Data.SqlClient.SqlConnection(connstring1); var da = new System.Data.SqlClient.SqlDataAdapter() { SelectCommand= new System.Data.SqlClient.SqlCommand(strSelect, c1) }; DataSet ds1 = new DataSet(); da.Fill(ds1, "Invoices"); using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) { zip.AddEntry(zipEntryName, (name,stream) => ds1.WriteXml(stream) ); zip.Save(zipFileName); }
using (var input = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite )) { using(Ionic.Zip.ZipFile zip = new Ionic.Zip.ZipFile()) { zip.AddEntry(zipEntryName, (name,output) => { byte[] buffer = new byte[BufferSize]; int n; while ((n = input.Read(buffer, 0, buffer.Length)) != 0) { // could transform the data here... output.Write(buffer, 0, n); // could update a progress bar here } }); zip.Save(zipFileName); } }
Private Sub WriteEntry (ByVal name As String, ByVal output As Stream) Using input As FileStream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite) Dim n As Integer = -1 Dim buffer As Byte() = New Byte(BufferSize){} Do While n <> 0 n = input.Read(buffer, 0, buffer.Length) output.Write(buffer, 0, n) Loop End Using End Sub Public Sub Run() Using zip = New ZipFile zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry)) zip.Save(zipFileName) End Using End Sub