Question

J'avais besoin d'un moyen de compresser des images au format .net, j'ai donc étudié la possibilité d'utiliser la classe .net GZipStream (ou DeflateStream). Cependant, j’ai trouvé que la décompression n’avait pas toujours été couronnée de succès, parfois les images se décompressaient correctement et d’autres fois, j’obtenais une erreur GDI + selon laquelle quelque chose était corrompu.

Après avoir étudié le problème, j’ai constaté que la décompression ne rendait pas tous les octets compressés. Donc, si je compressais 2257974 octets, je ne recevais parfois que 2257870 octets (nombres réels).

La chose la plus amusante est que parfois cela fonctionnerait. J'ai donc créé cette petite méthode de test qui compresse seulement 10 octets et maintenant je ne récupère plus rien du tout.

Je l’ai essayé avec les deux classes de compression GZipStream et DeflateStream et j’ai vérifié deux fois mon code pour déceler des erreurs éventuelles. J'ai même essayé de positionner le flux à 0 et de rincer tous les flux, mais sans succès.

Voici mon code:

    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();
    }
Était-ce utile?

La solution

Vous devez fermer () le ZipStream après avoir ajouté toutes les données à compresser. il conserve en interne un tampon d'octets non écrits (même si vous Flush () ) doit être écrit.

Plus généralement, Stream est IDisposable . Vous devez donc également utiliser chacun ... (oui, je sais que MemoryStream ne perdra aucune donnée, mais si vous ne prenez pas cette habitude, il vous mordra avec d'autres flux .

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())
    { ... }
}

[edit: mise à jour du commentaire] Ne pas utiliser comme MemoryStream - c’est toujours amusant, avec beaucoup de votes de part et d’autre de la clôture: mais finalement ...

(rhétorique - nous connaissons tous la réponse ...) Comment MemoryStream est-il implémenté? est-ce un octet [] (appartenant à .NET)? s'agit-il d'un fichier mappé en mémoire (appartenant au système d'exploitation)?

La raison pour laquelle vous n'utilisez pas c'est parce que vous laissez la connaissance des détails de l'implémentation interne modifier la façon dont vous codez par rapport à une API publique, c'est-à-dire que vous venez d'enfreindre les lois de l'encapsulation. L'API publique dit: Je suis IDisposable ; vous " possédez " moi; Par conséquent, il vous incombe de vous débarrasser de () lorsque vous avez terminé.

Autres conseils

De plus, n'oubliez pas que DeflateStream dans System.IO.Compression n'implémente pas l'algorithme de déflation le plus efficace. Si vous le souhaitez, il existe une alternative aux BCL GZipStream et DeflateStream; il est implémenté dans une bibliothèque entièrement gérée basée sur le code zlib, qui fonctionne mieux que le flux {Deflate, GZip} intégré à cet égard. [Mais vous devez toujours fermer () le flux pour obtenir le flux complet de bytestream. ]

Ces classes de flux sont livrées dans l'assemblage DotNetZlib, disponible dans la distribution DotNetZ à l'adresse http: //DotNetZip.codeplex. com / .

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top