Unable to create zip file using Ionic.Zip

2.1k Views Asked by At

I'm not sure where and what am I doing wrong, but the zip that I'm creating using DotNetZip library, is creating a zip file whose contents are blank. Or the size of file in zip is showing as 0Kb and unable to open it.

Code:

public static async Task DotNetZipFileAsync(MemoryStream stream, string bucket, List<List<string>> pdfFileSet, IAmazonS3 s3Client)
        {
           
            using Ionic.Zip.ZipFile zip = new ZipFile();
            foreach (var pdfFile in pdfFileSet)
            {
                foreach (var file in pdfFile)
                {
                    GetObjectRequest request = new GetObjectRequest
                    {
                        BucketName = bucket,
                        Key = file
                    };
                    
                    using GetObjectResponse response = await s3Client.GetObjectAsync(request);
                    using Stream responseStream = response.ResponseStream;
                    ZipEntry zipEntry = zip.AddEntry(file.Split('/')[^1], responseStream);
                    await responseStream.CopyToAsync(stream);
                }
            }
            zip.Save(stream);
            stream.Seek(0,SeekOrigin.Begin);
            await stream.CopyToAsync(new FileStream(@"C:\LocalRepo\Temp.zip", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite));
        }
    }
}
2

There are 2 best solutions below

14
Klaus Gütter On

Your code has at least two problems:

  1. The read stream is completely consumed by the await responseStream.CopyToAsync(stream). You could rewind the responseStream to cope with this, but saving the data into the memory stream is completely useless.

  2. The response stream is disposed before zip.Save is called.

What you could do: keep the streams open until Save is called and dispose them afterwards. As Alexey Rumyantsev discovered (see comments), also the GetObjectResponse objects need to be kept until the ZIP file is saved.

using Ionic.Zip.ZipFile zip = new ZipFile();
var disposables = List<IDisposable>();
try
{
    foreach (var pdfFile in pdfFileSet)
    {
        foreach (var file in pdfFile)
        {
            GetObjectRequest request = new GetObjectRequest
            {
                BucketName = bucket,
                Key = file
            };
            
            var response = await s3Client.GetObjectAsync(request);
            disposables.Add(response);
            var responseStream = response.ResponseStream;
            disposables.Add(responseStream);
            ZipEntry zipEntry = zip.AddEntry(file.Split('/')[^1], responseStream);
        }
    }
    using var fileStream = new FileStream(@"C:\LocalRepo\Temp.zip", FileMode.Create, FileAccess.Write);        
    zip.Save(fileStream);
}
finally
{
    foreach (var disposable in disposables)
    {
        disposable.Dispose();
    }
}

The documentation has some hints ony how this could be made smarter.

0
Aniruddha On
public static async Task DotNetZipFileAsync(string bucket, List<List<string>> pdfFileSet, IAmazonS3 s3Client)
{
    int read;
    using Ionic.Zip.ZipFile zip = new ZipFile();
    byte[] buffer = new byte[16 * 1024];
    
    foreach (var pdfFile in pdfFileSet)
    {
        foreach (var file in pdfFile)
        {
            GetObjectRequest request = new GetObjectRequest
            {
                BucketName = bucket,
                Key = file
            };

            using GetObjectResponse response = await s3Client.GetObjectAsync(request);
            using Stream responseStream = response.ResponseStream;
            using (MemoryStream ms = new MemoryStream())
            {
                while ((read = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                {
                    ms.Write(buffer, 0, read);
                }
                zip.AddEntry(file.Split('/')[^1], ms.ToArray());
            }
        }
    }
    using var fileStream = new FileStream(@"C:\LocalRepo\Temp.zip", FileMode.Create, FileAccess.Write);
    zip.Save(fileStream);
}