30 votes

Pourquoi mon C # gzip produit-il un fichier plus volumineux que Fiddler ou PHP?

Si je GZip ce texte:

Bonjour Tout Le Monde

par le biais de C# à l'aide de ce code:

Stream stream = new MemoryStream(Encoding.Default.GetBytes("Hello World"));
var compressedMemoryStream = new MemoryStream();
using (var gzipStream = new GZipStream(compressedMemoryStream, CompressionMode.Compress))
{
    stream.CopyTo(gzipStream);  
    gzipStream.Close(); 
} 

le flux résultant est de 133 octets de long

L'exécution de la même chaîne, soit par Fiddler's Utilities.GzipCompress ou cette page PHP , le résultat est à seulement 31 octets de long.

Dans les deux cas, l'entrée est de 11 octets, donc j'imagine que le PHP résultat est correct mais évidemment, cela signifie que je ne peux pas décompresser le PHP zip à partir de l'intérieur .NET, ou inversement. Pourquoi l' .La sortie NETTE de manière beaucoup plus grande?


En fait il s'avère que, bien que le résultat de PHP et le Violoneux sont de la même longueur qu'ils ne sont pas les mêmes. Je peux décompresser la version de PHP en .NET, mais pas de la Fiddler version. La page PHP décompresse tous les trois, donc il semble que il peut y avoir une incompatibilité entre le Violoniste et .NET implémentations de gzip.


Comme demandé j'ai téléchargé les trois sorties à dropbox ici.

Et ce sont les premières hexdumps de ces fichiers (pas sûr si elles sont vraiment toute utilisation de ce genre, mais je pense que cela montre que la différence entre le violon et la version de PHP est dans l'en-tête, plutôt que par la compression de données elle-même):

Fiddler:

0000-0010:  1f 8b 08 00-c2 e6 ff 4f-00 ff f3 48-cd c9 c9 57  .......O ...H...W
0000-001f:  08 cf 2f ca-49 01 00 56-b1 17 4a 0b-00 00 00     ../.I..V ..J....

PHP:

0000-0010:  1f 8b 08 00-00 00 00 00-00 03 f3 48-cd c9 c9 57  ........ ...H...W
0000-001f:  08 cf 2f ca-49 01 00 56-b1 17 4a 0b-00 00 00     ../.I..V ..J....

C#:

0000-0010:  1f 8b 08 00-00 00 00 00-04 00 ec bd-07 60 1c 49  ........ .....`.I
0000-0020:  96 25 26 2f-6d ca 7b 7f-4a f5 4a d7-e0 74 a1 08  .%&/m.{. J.J..t..
0000-0030:  80 60 13 24-d8 90 40 10-ec c1 88 cd-e6 92 ec 1d  .`.$..@. ........
0000-0040:  69 47 23 29-ab 2a 81 ca-65 56 65 5d-66 16 40 cc  iG#).*.. eVe]f.@.
0000-0050:  ed 9d bc f7-de 7b ef bd-f7 de 7b ef-bd f7 ba 3b  .....{.. ..{....;
0000-0060:  9d 4e 27 f7-df ff 3f 5c-66 64 01 6c-f6 ce 4a da  .N'...?\ fd.l..J.
0000-0070:  c9 9e 21 80-aa c8 1f 3f-7e 7c 1f 3f-22 be 9d 97  ..!....? ~|.?"...
0000-0080:  65 95 7e b7-aa cb d9 ff-13 00 00 ff-ff 56 b1 17  e.~..... .....V..
0000-0085:  4a 0b 00 00-00

56voto

Mark Adler Points 15178

Préface: .NET les utilisateurs ne doivent pas utiliser l'fournis par Microsoft GZipStream ou DeflateStream classes dans toutes les circonstances, à moins que Microsoft ne les remplace complètement avec quelque chose qui fonctionne. Utiliser la bibliothèque de DotNetZip à la place.

Mise à jour Préface: L' .NET Framework 4.5 et, plus tard, ont résolu le problème de compression, et GZipStream et DeflateStream utilisation zlib dans ces versions. Je ne sais pas si le CRC problème mentionné ci-dessous a été corrigé.

Une autre mise à jour: Le CRC problème non seulement n'est pas fixe, mais Microsoft a décidé qu'ils ne sera pas corrigé ça!

C'est l'un de plusieurs bugs dans GZipStream. Pas d'auto-respect de gzip compresseur doit jamais produire 133 octets de sortie à partir de 11 octets d'entrée. Voir mes commentaires sur Pourquoi BCL GZipStream (avec StreamReader) pas de détecter de manière fiable des Erreurs de Données avec CRC32? .

Ce qui se passe à l'intérieur, c'est que GZipStream n'est pas à l'aide de la statique ou de méthodes stockées, qui serait de produire des données compressées environ la même taille que les données d'entrée (sur le dessus de ce qui serait ajouté 18 octets d'en-tête gzip et de la remorque). C'est plutôt à l'aide de la méthode dynamique, qui crée un très grand code d'en-tête de descripteur pour un très petit nombre de codes. C'est simplement un bug / très mauvaise mise en œuvre.

Mise à jour:

Avec le hex dumps, je peux donner un peu d'analyse. Tout d'abord, la Violoniste et php de sortie sont correct et approprié. La seule différence entre eux est dans l'en-tête gzip, en particulier le timestamp ensemble dans un violon, mais pas en php, et l'origine de l'exploitation de l'ensemble du système en php, mais pas dans un violon. Pour le 13 octets de données compressées sont identiques, et peut être représenté comme (à l'aide de mon infgen programme de démonter dégonfler cours d'eau):

last
static
literal 'Hello World
end

qui est exactement comme il devrait être. Un seul bloc statique, qui ne nécessite pas de code de descripteurs, et tout simplement de codage de tous les octets comme des littéraux. (Pas de matches de précédentes chaînes avec des longueurs et des distances.)

La sortie de GZipStream sur l'autre main est un horrible gâchis de plusieurs façons. Les données compressées sont:

dynamic
code 3 5
code 4 5
code 5 4
code 6 4
code 7 4
code 8 3
code 9 3
code 10 4
code 11 4
code 12 4
code 13 4
code 14 3
code 16 3
litlen 0 14
litlen 1 14
litlen 2 14
litlen 3 14
litlen 4 14
litlen 5 14
litlen 6 14
litlen 7 14
litlen 8 14
litlen 9 12
litlen 10 6
litlen 11 14
litlen 12 14
litlen 13 14
litlen 14 14
litlen 15 14
litlen 16 14
litlen 17 14
litlen 18 14
litlen 19 14
litlen 20 14
litlen 21 14
litlen 22 14
litlen 23 14
litlen 24 14
litlen 25 14
litlen 26 14
litlen 27 14
litlen 28 14
litlen 29 14
litlen 30 13
litlen 31 14
litlen 32 6
litlen 33 14
litlen 34 10
litlen 35 12
litlen 36 14
litlen 37 14
litlen 38 13
litlen 39 10
litlen 40 8
litlen 41 9
litlen 42 11
litlen 43 10
litlen 44 7
litlen 45 8
litlen 46 7
litlen 47 9
litlen 48 8
litlen 49 8
litlen 50 8
litlen 51 9
litlen 52 8
litlen 53 9
litlen 54 10
litlen 55 9
litlen 56 8
litlen 57 9
litlen 58 9
litlen 59 8
litlen 60 9
litlen 61 10
litlen 62 8
litlen 63 14
litlen 64 14
litlen 65 8
litlen 66 9
litlen 67 8
litlen 68 9
litlen 69 8
litlen 70 9
litlen 71 10
litlen 72 11
litlen 73 8
litlen 74 11
litlen 75 14
litlen 76 9
litlen 77 10
litlen 78 9
litlen 79 10
litlen 80 9
litlen 81 12
litlen 82 9
litlen 83 9
litlen 84 9
litlen 85 10
litlen 86 12
litlen 87 11
litlen 88 14
litlen 89 14
litlen 90 12
litlen 91 11
litlen 92 14
litlen 93 11
litlen 94 14
litlen 95 14
litlen 96 14
litlen 97 6
litlen 98 7
litlen 99 7
litlen 100 7
litlen 101 6
litlen 102 8
litlen 103 8
litlen 104 7
litlen 105 6
litlen 106 12
litlen 107 9
litlen 108 6
litlen 109 7
litlen 110 7
litlen 111 6
litlen 112 7
litlen 113 13
litlen 114 6
litlen 115 6
litlen 116 6
litlen 117 7
litlen 118 8
litlen 119 8
litlen 120 9
litlen 121 8
litlen 122 11
litlen 123 13
litlen 124 12
litlen 125 13
litlen 126 13
litlen 127 14
litlen 128 14
litlen 129 14
litlen 130 14
litlen 131 14
litlen 132 14
litlen 133 14
litlen 134 14
litlen 135 14
litlen 136 14
litlen 137 14
litlen 138 14
litlen 139 14
litlen 140 14
litlen 141 14
litlen 142 14
litlen 143 14
litlen 144 14
litlen 145 14
litlen 146 14
litlen 147 14
litlen 148 14
litlen 149 14
litlen 150 14
litlen 151 14
litlen 152 14
litlen 153 14
litlen 154 14
litlen 155 14
litlen 156 14
litlen 157 14
litlen 158 14
litlen 159 14
litlen 160 14
litlen 161 14
litlen 162 14
litlen 163 14
litlen 164 14
litlen 165 14
litlen 166 14
litlen 167 14
litlen 168 14
litlen 169 14
litlen 170 14
litlen 171 14
litlen 172 14
litlen 173 14
litlen 174 14
litlen 175 14
litlen 176 14
litlen 177 14
litlen 178 14
litlen 179 14
litlen 180 14
litlen 181 14
litlen 182 14
litlen 183 14
litlen 184 14
litlen 185 14
litlen 186 14
litlen 187 14
litlen 188 14
litlen 189 14
litlen 190 14
litlen 191 14
litlen 192 14
litlen 193 14
litlen 194 14
litlen 195 14
litlen 196 14
litlen 197 14
litlen 198 14
litlen 199 14
litlen 200 14
litlen 201 14
litlen 202 14
litlen 203 14
litlen 204 14
litlen 205 14
litlen 206 14
litlen 207 14
litlen 208 14
litlen 209 14
litlen 210 14
litlen 211 14
litlen 212 14
litlen 213 14
litlen 214 14
litlen 215 14
litlen 216 14
litlen 217 14
litlen 218 14
litlen 219 14
litlen 220 14
litlen 221 14
litlen 222 14
litlen 223 14
litlen 224 14
litlen 225 14
litlen 226 14
litlen 227 14
litlen 228 14
litlen 229 14
litlen 230 14
litlen 231 14
litlen 232 14
litlen 233 14
litlen 234 14
litlen 235 14
litlen 236 14
litlen 237 14
litlen 238 14
litlen 239 14
litlen 240 14
litlen 241 14
litlen 242 14
litlen 243 13
litlen 244 13
litlen 245 13
litlen 246 14
litlen 247 13
litlen 248 14
litlen 249 13
litlen 250 14
litlen 251 13
litlen 252 14
litlen 253 14
litlen 254 14
litlen 255 14
litlen 256 14
litlen 257 4
litlen 258 3
litlen 259 4
litlen 260 4
litlen 261 4
litlen 262 5
litlen 263 5
litlen 264 5
litlen 265 5
litlen 266 5
litlen 267 6
litlen 268 6
litlen 269 5
litlen 270 6
litlen 271 7
litlen 272 8
litlen 273 8
litlen 274 9
litlen 275 10
litlen 276 9
litlen 277 10
litlen 278 12
litlen 279 11
litlen 280 12
litlen 281 14
litlen 282 14
litlen 283 14
litlen 284 12
litlen 285 11
dist 0 6
dist 1 10
dist 2 11
dist 3 11
dist 4 9
dist 5 8
dist 6 8
dist 7 8
dist 8 7
dist 9 7
dist 10 5
dist 11 6
dist 12 4
dist 13 5
dist 14 4
dist 15 5
dist 16 4
dist 17 5
dist 18 4
dist 19 4
dist 20 4
dist 21 4
dist 22 4
dist 23 4
dist 24 4
dist 25 5
dist 26 4
dist 27 5
dist 28 5
dist 29 5
literal 'Hello World
end
!
last
stored
end

Donc, qu'est-ce que tout cela? Les données réelles sont juste à la ligne près de la fin "lettre" Hello World", qui vient de codes de chaque octet de l'entrée. De ce qui précède, il est une description d'un ensemble de codes de Huffman pour les littéraux, des longueurs et des distances. Ici sont les choses de mal avec elle:

  • Tout d'abord, il ne devrait pas être à l'aide de la dynamique de tous. Décrire l'ensemble des codes prend environ 100 octets. C'est précisément pourquoi les dégonfler format offre un ensemble pré-défini des codes utilisés dans les blocs statiques. Le compresseur doit sélectionner un bloc statique dans ce cas (qui est ce que le php et le Violoneux, sont en train de faire).
  • Deuxièmement, tous les possibles de code est défini, même si la grande majorité ne sont jamais utilisés! Lors de l'utilisation d'un bloc dynamique, un bon compresseur ne définira les codes pour les littéraux, des longueurs et des distances effectivement utilisés dans ce bloc. Dans ce cas, il n'y a pas des longueurs ou des distances, et seulement huit littéraux utilisé (H, e, l, o, de l'espace, w, r et d). Au lieu de cela, il procède à définir 256 littérale des codes, des 29 codes de longueur et de 30 à distance des codes. Je devine que certains l'expérimentation montrent que la dynamique de l'en-tête de GZipStream est toujours le même, dans ce cas, il n'est pas encore dynamique, ce qui est le point de l'ensemble!
  • Troisièmement, il le jette dans une vides inutiles stockées bloc à la fin. Le premier bloc ont été marqués comme le dernier bloc.

Tous ces points pour le simple fait que celui qui a écrit ce GZipStream code a été, pour le dire comme poliment que je peux, dépourvue de toute compréhension de la dégonfler format de la compression ou en général. Ils ont choisi de ne produire que des blocs dynamiques (à l'exception d'un vide statique bloc à la fin), pour produire la même dynamique de l'en-tête à chaque fois (je crois), en battant le but de blocs dynamiques, et pour ne pas les déranger pour savoir si le bloc courant est le dernier, exigeant de mettre un bloc vide pour marquer la fin.

Comme indiqué ailleurs, ce ne sont pas les seuls problèmes avec GZipStream. Il ne peut même pas l'utiliser correctement le CRC-32 destinés à détecter la corruption des ruisseaux.

Vraiment perplexe, c'est la raison pour laquelle Microsoft attribué à quelqu'un incompétent pour écrire un gzip compresseur et décompresseur, mais plutôt pourquoi ils ont attribué quelqu'un de l'écrire! Il est disponible gratuitement code, zlib, qui a une très libéral de licence qui permet l'utilisation commerciale sans l'attribution. Ce code a été largement déployées depuis près de deux décennies, et fait toutes les choses qu'il est censé faire correctement et efficacement. Plus tout le reste utilise zlib, y compris php, et je soupçonne que Fiddler ainsi.

2voto

Henrik Ripa Points 325

GZipStream ajoute un en-tête de 10 octets et un pied de page de 8 octets aux données compressées comme décrit dans les spécifications RFC 1952 . Cela donne un résultat long de 133 octets.

La page PHP à laquelle vous avez lié ajoute également le même en-tête / pied de page de 18 octets si demandé ( GZIP-compatible encoding? ). Si vous l'utilisez, cela donne un résultat long de 31 octets.

Sans en-tête / pied de page, la différence entre eux est de 125 contre 13 octets.

2voto

zeFrenchy Points 4154

Quel que soit le contenu que vous nourrissez dans GZipStream vous obtenez les mêmes frais généraux. GZipStream est identique pour la première 108 octets

1f 8b 08 00 00 00 00 00 04 00 ec bd 07 60 1c 49
96 25 26 2f 6d ca 7b 7f 4a f5 4a d7 e0 74 a1 08
80 60 13 24 d8 90 40 10 ec c1 88 cd e6 92 ec 1d
69 47 23 29 ab 2a 81 ca 65 56 65 5d 66 16 40 cc
ed 9d bc f7 de 7b ef bd f7 de 7b ef bd f7 ba 3b
9d 4e 27 f7 df ff 3f 5c 66 64 01 6c f6 ce 4a da 
c9 9e 21 80 aa c8 1f 3f 7e 7c 1f 3f 22 >>>

Jusqu'à 1f 8b 08 00 00 00 00 00 04 00 correspond à la définition standard ( ttp://www.faqs.org/rfcs/rfc1952.html ). Le reste de la partie fixe a été expliqué par @marc-adler dans Pourquoi BCL GZipStream (avec StreamReader) pas de détecter de manière fiable des Erreurs de Données avec CRC32?

0voto

Matthew1471 Points 13

Partiellement brevets:

La raison pour laquelle le niveau de compression de ne pas être aussi bonne qu'avec certaines autres applications, c'est que le plus efficace des algorithmes de compression sur le marché sont tous protégés par un brevet. .net utilise un non-breveté un.

et

Eh bien, l'explication que j'ai eu (de quelqu'un de chez MS), quand j'ai demandé la même chose, c'était qu'elle devait faire avec Microsoft de ne pas être en mesure d'utiliser l'algorithme GZip sans le modifier; en raison de brevet/licence.

http://social.msdn.microsoft.com/Forums/fr-FR/c5f0b53c-a2d5-4407-b43b-9da8d39c01df/why-do-gzipstream-compression-ratio-so-bad?forum=netfxbcl

Initiale, je soupçonne Microsoft gzip mise en œuvre; je savais qu'ils ont mis en œuvre l'algorithme Deflate qui n'est pas le plus efficace mais est libre de droits.

http://challenge-me.ws/post/2010/11/05/Do-Not-Take-Microsofts-Code-for-Granted.aspx

-2voto

Robbie Dee Points 724

Les outils de compression modernes utilisent généralement plusieurs stratégies de compression. Avec Winzip et WinRAR, etc., vous obtiendrez généralement des options telles que:

  • Compression maximale
  • Le plus rapide
  • Ordinaire

Si vous deviez faire de même, vous seriez probablement en mesure de compresser davantage le fichier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X