Domanda

System.IO.Compression.GZipStream o System.IO.Compression.Deflate sono compatibili con la compressione zlib?

È stato utile?

Soluzione

Da MSDN informazioni su System.IO.Compression.GZipStream:

Questa classe rappresenta il formato dati gzip, che utilizza un algoritmo standard del settore per la compressione e decompressione dei file senza perdita di dati.

Dal Domande frequenti su zlib:

Le funzioni gz* in zlib invece utilizzano il formato gzip.

Quindi zlib e GZipStream dovrebbero essere interoperabili, ma solo se usi le funzioni zlib per gestire il formato gzip.

Secondo quanto riferito, System.IO.Compression.Deflate e zlib non sono interoperabili.

Se hai bisogno di gestire file zip (probabilmente non lo fai, ma qualcun altro potrebbe averne bisogno) devi usare SharpZipLib o un'altra libreria di terze parti.

Altri suggerimenti

DotNetZip include un DeflateStream, uno ZlibStream e un GZipStream, per gestire RFC 1950, 1951 e 1952.Tutti utilizzano l'algoritmo DEFLATE ma i byte di framing e di intestazione sono diversi per ciascuno.

Come vantaggio, i flussi in DotNetZip non presentano l'estensione anomalia dell'espansione della dimensione dei dati sotto compressione, riportato rispetto ai flussi integrati.Inoltre, non esiste ZlibStream integrato, mentre DotNetZip te lo offre, per una buona interoperabilità con zlib.

Ho riscontrato questo problema con gli oggetti Git.In quel caso particolare, memorizzano gli oggetti come blob sgonfiati con un'intestazione Zlib, che è documentata in RFC1950.È possibile creare un BLOB compatibile creando un file che contenga:

  • Due byte di intestazione (CMF e FLG da RFC 1950) con i valori 0x78 0x01
    • CM = 8 = sgonfiare
    • CINFO = 7 = finestra da 32Kb
    • FCHECK = 1 = bit di checksum per questa intestazione
  • L'output del C# DeflateStream
  • Un checksum Adler32 dei dati di input nel file DeflateStream, formato big-endian (prima MSB)

Ho realizzato la mia implementazione di Adler

public class Adler32Computer
{
    private int a = 1;
    private int b = 0;

    public int Checksum
    {
        get
        {
            return ((b * 65536) + a);
        }
    }

    private static readonly int Modulus = 65521;

    public void Update(byte[] data, int offset, int length)
    {
        for (int counter = 0; counter < length; ++counter)
        {
            a = (a + (data[offset + counter])) % Modulus;
            b = (b + a) % Modulus;
        }
    }
}

E questo è praticamente tutto.

Ho utilizzato GZipStream per comprimere l'output di .NET XmlSerializer e ha funzionato perfettamente per decomprimere il risultato con gunzip (in Cygwin), winzip e un altro GZipStream.

Per riferimento, ecco cosa ho fatto nel codice:

FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write);
using (GZipStream gzStream = new GZipStream(fs, CompressionMode.Compress))
{
  XmlSerializer serializer = new XmlSerializer(typeof(MyDataType));
  serializer.Serialize(gzStream, myData);
}

Quindi, per decomprimere in C#

FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
using (Stream input = new GZipStream(fs, CompressionMode.Decompress))
{
   XmlSerializer serializer = new XmlSerializer(typeof(MyDataType));
   myData = (MyDataType) serializer.Deserialize(input);
}

L'utilizzo dell'utilità 'file' in Cygwin rivela che esiste effettivamente una differenza tra lo stesso file compresso con GZipStream e con GNU GZip (probabilmente informazioni sull'intestazione come altri hanno affermato in questo thread).Questa differenza, tuttavia, sembra non avere importanza nella pratica.

gzip è deflate + alcuni dati di intestazione/piè di pagina, come checksum e lunghezza, ecc.Quindi non sono compatibili nel senso che un metodo può utilizzare un flusso dell'altro, ma utilizzano lo stesso algoritmo di compressione.

Si limitano a comprimere i dati utilizzando algoritmi zlib o deflate, ma non forniscono l'output per alcuni formati di file specifici.Ciò significa che se memorizzi lo stream così com'è sul disco rigido molto probabilmente non sarai in grado di aprirlo utilizzando qualche applicazione (gzip o winrar) perché le intestazioni dei file (numero magico, ecc.) non sono incluse nello stream e dovresti scriviteli tu stesso.

A partire da .NET Framework 4.5 il System.IO.Compression.DeflateStream la classe utilizza la libreria zlib.

Da quello della classe Articolo MSDN:

Questa classe rappresenta l'algoritmo Deflate, un algoritmo standard del settore per la compressione e decompressione di file senza perdita di dati.A partire da .NET Framework 4.5, la classe DeflateStream usa la libreria zlib.Di conseguenza, fornisce un algoritmo di compressione migliore e, nella maggior parte dei casi, un file compresso più piccolo rispetto a quello fornito nelle versioni precedenti di .NET Framework.

Sono d'accordo con andrea.Probabilmente non sarai in grado di aprire il file in uno strumento esterno, ma se quello strumento prevede uno streaming potresti essere in grado di usarlo.Potresti anche sgonfiare nuovamente il file utilizzando la stessa classe di compressione.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top