c# GZipStream e DeflateStream non decomprimeranno tutti i byte




image compression (2)

Avevo bisogno di un modo per comprimere le immagini in .net così ho cercato di usare la .net classe GZipStream (o DeflateStream). Tuttavia ho scoperto che la decompressione non ha sempre avuto successo, a volte le immagini si decomprimevano bene e altre volte ottenevo un errore GDI + che qualcosa è danneggiato.

Dopo aver esaminato il problema, ho scoperto che la decompressione non restituiva tutti i byte compressi. Quindi se compresso 2257974 byte a volte tornerei indietro solo 2257870 byte (numeri reali).

La cosa più divertente è che a volte potrebbe funzionare. Così ho creato questo piccolo metodo di prova che comprime solo 10 byte e ora non ritorno niente.

Ho provato con entrambe le classi di compressione GZipStream e DeflateStream e ho ricontrollato il mio codice per possibili errori. Ho persino provato a posizionare il flusso su 0 ea scovare tutti i flussi ma senza fortuna.

Ecco il mio codice:

    public static void TestCompression()
    {
        byte[] test = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

        byte[] result = Decompress(Compress(test));

        // This will fail, result.Length is 0
        Debug.Assert(result.Length == test.Length);
    }

    public static byte[] Compress(byte[] data)
    {
        var compressedStream = new MemoryStream();
        var zipStream = new GZipStream(compressedStream, CompressionMode.Compress);
        zipStream.Write(data, 0, data.Length);
        return compressedStream.ToArray();
    }

    public static byte[] Decompress(byte[] data)
    {
        var compressedStream = new MemoryStream(data);
        var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress);
        var resultStream = new MemoryStream();

        var buffer = new byte[4096];
        int read;

        while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0) {
            resultStream.Write(buffer, 0, read);
        }

        return resultStream.ToArray();
    }

Inoltre, tieni presente che DeflateStream in System.IO.Compression non implementa l'algoritmo di deflate più efficiente. Se vuoi, c'è un'alternativa a BCL GZipStream e DeflateStream; è implementato in una libreria completamente gestita basata su codice zlib, che funziona meglio del flusso incorporato {Deflate, GZip} Stream a questo riguardo. [Ma devi comunque chiudere () lo stream per ottenere l'intero puntatore. ]

Queste classi di flusso vengono fornite nell'assemblaggio DotNetZlib, disponibile nella distribuzione DotNetZip all'indirizzo http://DotNetZip.codeplex.com/ .


Devi Close() lo ZipStream dopo aver aggiunto tutti i dati che vuoi comprimere; mantiene un buffer di byte non scritti internamente (anche se si Flush() ) che deve essere scritto.

Più in generale, Stream è IDisposable , quindi dovresti usare anche ognuno ... (sì, so che MemoryStream non perderà alcun dato, ma se non ti abitui a questa abitudine, ti morderà con altri Stream s).

public static byte[] Compress(byte[] data)
{
    using (var compressedStream = new MemoryStream())
    using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress))
    {
        zipStream.Write(data, 0, data.Length);
        zipStream.Close();
        return compressedStream.ToArray();
    }
}

public static byte[] Decompress(byte[] data)
{
    using(var compressedStream = new MemoryStream(data))
    using(var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
    using (var resultStream = new MemoryStream())
    { ... }
}

[modifica: aggiornamento re commento] Non using cose come MemoryStream - questo è sempre divertente, con molti voti su entrambi i lati del recinto: ma ultimo ...

(retorico - conosciamo tutti la risposta ...) Come viene implementato MemoryStream ? è un byte [] (di proprietà di .NET)? si tratta di un file mappato in memoria (di proprietà del sistema operativo)?

Il motivo per cui non lo stai using è perché stai lasciando che la conoscenza dei dettagli di implementazione interna cambi il modo in cui codifichi contro un'API pubblica, ovvero hai appena infranto le leggi dell'incapsulamento. L'API pubblica dice: I am IDisposable ; tu mi possiedi; quindi, il tuo lavoro è Dispose() me quando hai finito.





bitmap