Bedford
Bedford

Reputation: 1186

Compressing an object in memory with System.IO.Compression in C#

I'm trying to serialize an instance of a class (let's call it Car) into an xml and compress it in memory to a zip file with a single file entry in it. I'm using the System.IO.Compression.ZipArchive class to do it:

private byte[] CompressCar(Car car)
{
    using (var carStream = new MemoryStream())
    using (var zipStream = new MemoryStream())
    using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
    {
        new XmlSerializer(typeof(Car)).Serialize(carStream, car);
        ZipArchiveEntry entry = archive.CreateEntry("car.xml", CompressionLevel.Optimal);
        using (var zippedFileStream = entry.Open())
        {
            carStream.Seek(0, SeekOrigin.Begin);
            carStream.CopyTo(zippedFileStream);
        }
        return zipStream.ToArray();
    }
}

When I save the compressed bytes to a file and later try to open it with Windows Explorer I get an error: enter image description here What am I doing wrong here?

I looked for other StackOverflow entries but I just couldn't find anything that would solve my problem. I want to compress it in memory rather than using a temporary file.

Upvotes: 1

Views: 1133

Answers (1)

dbc
dbc

Reputation: 116680

You need to dispose the ZipArchive before returning the underlying zipStream.ToArray(). E.g., you could extract the following helper method:

public static class SerializationExtensions
{
    public static byte[] ToCompressedXmlZipArchive<T>(T root, string entryName)
    {
        using (var zipStream = new MemoryStream())
        {
            using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create))
            {
                var entry = archive.CreateEntry(entryName, CompressionLevel.Optimal);
                using (var zippedFileStream = entry.Open())
                {
                    new XmlSerializer(typeof(T)).Serialize(zippedFileStream, root); // Possibly use root.GetType() instead of typeof(T)
                }
            }
            return zipStream.ToArray();
        }
    }
}

And then your method becomes:

    private byte[] CompressCar(Car car)
    {
        return SerializationExtensions.ToCompressedXmlZipArchive(car, "car.xml");
    }

Upvotes: 3

Related Questions