Search code examples
c#sharpziplib

SharpZipLib - adding a ZipEntry to a ZipFile throws a ZipException


I'm trying to create ZIP with file from in-memory string and save it. Here is my code so far:

var zip = ZipFile.Create(Path.Combine(outputPath, fileName));
zip.BeginUpdate();

var fileStream = new MemoryStream(Encoding.Default.GetBytes(myStringVariable));
var outputMemStream = new MemoryStream();
var zipStream = new ZipOutputStream(outputMemStream);
var zipEntry = new ZipEntry("file.html");

zipEntry.DateTime = DateTime.Now;
zipStream.PutNextEntry(zipEntry);
StreamUtils.Copy(fileStream, zipStream, new byte[4096]);
zipStream.CloseEntry();
zip.Add(zipEntry);

zip.CommitUpdate();
zip.Close();

However it breaks on zip.Add(zipEntry); and throws exception:

ZipException - Entry cannot have any data

Somehow I cannot figure out what's wrong.


Solution

  • The ZipFile.Add method override you're using is for adding directories, volume labels, etc. to a zip file: it explicitly throws a ZipException if you pass a ZipEntry containing data.

    As per the documentation if you want to add in-memory data to a ZipFile, you need to use the Add(IStaticDataSource dataSource, string entryName) override. You'll also need to create an implementation of IStaticDataSource (the one below is taken from the documentation page).

    So your code would be something like:

    void Main()
    {
        string outputPath = @"C:\Scratch\test.zip";
        string myStringVariable = "<html><head><title>Title</title></head><body>Hello World</body></html>";
    
        var zip = ZipFile.Create(outputPath);
        zip.BeginUpdate();
    
        var fileStream = new MemoryStream(Encoding.Default.GetBytes(myStringVariable));
    
        var dataSource = new CustomStaticDataSource();
        dataSource.SetStream(fileStream);
    
        zip.Add(dataSource, "file.html");
    
        zip.CommitUpdate();
        zip.Close();
    }
    
    public class CustomStaticDataSource : IStaticDataSource {
        private Stream _stream;
        // Implement method from IStaticDataSource
        public Stream GetSource() {
            return _stream;
        }
    
        // Call this to provide the memorystream
        public void SetStream(Stream inputStream) {
            _stream = inputStream;
            _stream.Position = 0;
        }
    }