JsonSerializer failing to write to a GZipStream

I'm trying to serialize very large object directly to a zip stream. I manage to do this by serializing to a file stream in an intermediate step, loading it back and then compressing it.

I've also tried compressing directly to a memory stream and it works. But when i use a GZipStream I'm always left with an "unfinished" object, the data is there it's correctly formatted up to the point where it ends unexpectedly. It's not for lack of flushing buffers since I've already tried flushing everything.

Simplified sample code:

internal static byte[] SerializeAndCompress(object objectToSerialize)
{
    using(var memStream = new MemoryStream())
    using (var zipStream = new GZipStream(memStream, CompressionMode.Compress, true))
    using (var streamWriter = new StreamWriter(zipStream))
    using (var jsonWriter = new JsonTextWriter(streamWriter))
    {
        var jsonSerializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Newtonsoft.Json.Formatting.None };

        jsonSerializer.Serialize(jsonWriter, objectToSerialize);
        jsonWriter.Flush();

        return memStream.ToArray();
    }
}

Thanks.

Jon Skeet
people
quotationmark

Rather than flushing the writer, I suggest you close it completely. That way the GZipStream knows there's no more data to write and can add any appropriate checksums or whatever it needs to do.

You could either call Close explicitly, or put it between the closing parts of using statements:

using(var memStream = new MemoryStream())
{
    using (var zipStream = new GZipStream(memStream, CompressionMode.Compress, true))
    using (var streamWriter = new StreamWriter(zipStream))
    using (var jsonWriter = new JsonTextWriter(streamWriter))
    {
        var jsonSerializer = new JsonSerializer { ContractResolver = new CamelCasePropertyNamesContractResolver(), Formatting = Newtonsoft.Json.Formatting.None };

        jsonSerializer.Serialize(jsonWriter, objectToSerialize);
    }
    return memStream.ToArray();
}

Note that by the time you call ToArray, the MemoryStream will already be closed, but that's okay - the data will still be there.

people

See more on this question at Stackoverflow