here's what you are doing wrong: you have several pending calls for ZipEntry.OpenReader () in one instance of ZipFile. You can get no more than one pending ZipEntry.OpenReader ().
Here's why: there is only one Stream object created when instantiating the specified zip file using ZipFile.Read () or a new ZipFile () that passes the name of an existing file. When you call ZipEntry.OpenReader (), it causes Seek () in the Stream object to move the file pointer to the beginning of the compressed stream for this particular record. When you call ZipEntry.OpenReader () again, it leads to another search () in another place in the stream. Thus, adding records and calling OpenReader () in a row, you call Seek () several times, but only the latter will be valid. The cursor stream will be placed at the beginning of the data for the record corresponding to the last call to ZipEntry.OpenReader ().
To fix this: cancel your approach. The easiest way to create a new zip file with fewer entries than an existing zip file is as follows: create an instance of ZipFile by reading the existing file, then delete the entries you do not need, then call ZipFile.Save () on the new path.
using (var zip = ZipFile.Read("c:\\dir\\path\\to\\existing\\zipfile.zip")) { foreach (var name in namesToRemove)
EDIT
What it does at the time of calling Save (): the library reads the raw compressed data for the records that you did NOT delete from the file system file, and writes them to a new archive file. This is very fast, because it does not decompress or recompress each entry to place it in a new, smaller zip file. It basically reads fragments of binary data from the source zip file and combines them together to form a new, smaller zip file.
To create multiple smaller files, you can do this again with the original zip file; just wrap it in a loop and change the files you delete and the file name of the new, smaller archive. Reading an existing zip file is also pretty fast.
Alternatively, you can unzip and extract each entry, and then recompress and write the entry to a new zip file. This is far, but it is possible. In this case, for each smaller zip file you want to create, you will need to create two instances of ZipFile. Open the first by reading the original zip archive. For each record that you want to save, create a MemoryStream, extract the contents of the record into this MemoryStream and do not forget to call Seek () in the mem stream to reset the cursor to the memory stream. Then, using the second instance of ZipFile, call AddEntry (), using this MemoryStream as the source for the added record. Call ZipFile.Save () only in the second instance.
using (var orig = ZipFile.Read("C:\\whatever\\OriginalArchive.zip")) { using (var smaller = new ZipFile()) { foreach (var name in entriesToKeep) { var ms = new MemoryStream(); orig[name].Extract(ms);
This works, but it involves decompressing and recompressing every record that falls into a smaller zip, which is inefficient and unnecessary.
If you don't mind the inefficiency of decompression and recompression, there is an alternative you can use: call overload ZipFile.AddEntry (), which accepts the opener and closer delegates . This means deferring the call to OpenReader () until the record is written to a new, smaller zip file. The effect is that you only have one pending OpenReader () at a time.
using(ZipFile original = ZipFile.Read("C:\\path.to\\original\\Archive.zip"), smaller = new ZipFile()) { foreach (var name in entriesToKeep) { zip.AddEntry(zipEntryName, (name) => original[name].OpenReader(), null); } smaller.Save("C:\\path.to\\smaller\\Archive.zip"); }
It is still inefficient because each record is unpacked and re-compressed, but it is slightly less inefficient.