当前位置: 首页 > 知识库问答 >
问题:

为什么我的C#gzip产生比Fiddler或PHP更大的文件?

高夜洛
2023-03-14

如果我GZip这个文本:

你好,世界

通过C#使用此代码:

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(); 
} 

生成的流长度为133字节

通过Fiddler的实用程序运行相同的字符串。gzip压缩或此PHP页面,结果只有31字节长。

在这两种情况下,输入都是11字节,因此我认为PHP结果是正确的,但显然这意味着我无法从内部解压缩PHP zip。NET或visa反之亦然。为什么会这样。净产出如此之大?

事实证明,虽然PHP和Fiddler的结果是相同的长度,但它们并不相同。我可以在中解压缩PHP版本。NET,但不是Fiddler版本。PHP页面将对这三个文件进行解压缩,因此看起来Fiddler和的文件可能不兼容。NET的gzip实现。

根据要求,我已经将三个输出上传到这里的dropbox。

这些是这些文件的原始hexDumps(不确定它们是否真的有这样的用途,但我认为这表明fiddler和PHP版本之间的区别在于头,而不是压缩数据本身):

小提琴手:

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

共有3个答案

沃瑾瑜
2023-03-14

无论您向GZipStream提供什么内容,您都会得到相同的开销。GZipStream的前108个字节看起来完全相同

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 >>>

最多1f8b08 00 00 00 00 00 04 00符合标准定义(ttp://www.faqs.org/rfcs/rfc1952.html)。在为什么BCL GZipStream(使用StreamReader)不能可靠地检测CRC32的数据错误?

宁兴修
2023-03-14

GZipStream将10字节的页眉和8字节的页脚添加到压缩数据中,如RFC 1952规范所述。这将产生一个133字节长的结果。

如果要求,您链接到的PHP页面也会添加相同的18字节页眉/页脚(GZIP兼容编码?)。如果您使用它,它会给出一个31字节长的结果。

如果没有页眉/页脚,它们之间的差异是125字节对13字节。

龚镜
2023-03-14

前言:。NET用户在任何情况下都不应该使用Microsoft提供的GZipStream或DeflateStream类,除非Microsoft完全用有效的东西替换它们。改为使用DotNetZip库。

前言更新:第二部分。NETFramework4.5及更高版本修复了压缩问题,GZipStream和deflatesttream在这些版本中使用zlib。我不知道下面提到的CRC问题是否已经解决。

另一个更新:CRC问题不仅没有解决,而且微软已经决定他们不会解决它!

这是GZipStream中的几个bug之一。任何自尊的gzip压缩器都不应该从11字节的输入中产生133字节的输出。请参阅我在为什么BCL GZipStream(使用StreamReader)不能可靠地使用CRC32检测数据错误上的评论。

内部发生的情况是GZipStream没有使用静态或存储方法,这两种方法都会产生与输入数据大小相同的压缩数据(在此基础上添加18个字节的gzip头和尾)。取而代之的是使用动态方法,它为极少数代码创建一个非常大的代码描述符头。这只是一个错误/非常糟糕的实现。

更新:

通过十六进制转储,我可以提供一些分析。首先,Fiddler和php输出都是正确的。它们之间的唯一区别在于gzip头,特别是在Fiddler中设置的时间戳,而不是在php中设置的时间戳,以及在php中设置的原始操作html" target="_blank">系统,而不是在Fiddler中设置的时间戳。对于这两个13字节的压缩数据是相同的,并可以表示为(使用我的infgen程序来拆解压缩流):

last
static
literal 'Hello World
end

这完全是应该的。单个静态块,不需要代码描述符,只需将所有字节编码为文字。(以前的字符串与长度和距离不匹配。)

另一方面,GZipStream的输出在几个方面是一个可怕的混乱。压缩数据为:

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

那这些是什么?实际数据只是结尾“文字‘你好世界’”附近的一行,它只是对输入的每个字节进行编码。前面是一组霍夫曼代码的文字、长度和距离描述。以下是它的问题:

  • 首先,它不应该使用动态。描述代码集大约需要100个字节。这正是deflate格式提供静态块中使用的预定义代码集的原因。在这种情况下,压缩器应该选择一个静态块(这就是php和Fiddler所做的)

所有这些都指向一个简单的事实,不管是谁写了这个GZipStream代码,我尽可能礼貌地说,他对通缩格式或压缩缺乏任何理解。他们选择只产生动态块(除了最后一个空的静态块),每次只产生相同的动态头(我想),违背了动态块的目的,并且懒得弄清楚当前块是否是最后一个,需要拿出一个空块来标记结尾。

正如其他地方所指出的,这些并不是GZipStream的唯一问题。它甚至不能正确地使用CRC-32来检测损坏的流。

真正令人困惑的不是为什么微软指定一个不称职的人来编写gzip压缩程序和解压缩程序,而是为什么他们指定任何人来编写它!有一个免费的代码zlib,它有一个非常自由的许可证,允许商业使用而无需归属。这段代码已经被广泛部署了近二十年,并且完成了它应该正确有效地完成的所有事情。其他大多数东西都使用zlib,包括php,我怀疑Fiddler也是如此。

 类似资料:
  • 问题内容: 为什么我的C ++插件中的Google V8 JavaScript引擎比Node.JS的运行速度明显慢? 我试图编写一些愚蠢的简单代码来在JavaScript中生成素数,并通过C ++插件在V8中直接在Node.JS中运行它。 我很震惊,因为两个都应该使用相同的JavaScript引擎并且都执行了相同的代码(时间以毫秒为单位,时间越短越好): 这是运行相同JavaScript代码的Ja

  • 问题内容: 我有一个2 GB的文件(),其中文件中的每一行都是一个单词,就像: 我需要编写一个程序来读取文件中的每个单词并打印单词计数。我使用Java和C 编写它,但结果令人惊讶:Java运行速度是C 的2.3倍。我的代码如下: C ++: 输出: Java: 输出: 在这种情况下,为什么Java比C 快?如何提高C 的性能? 问题答案: 您不是在比较同一件事。Java程序读取行,以换行符开头,而

  • 问题内容: 我在WAMP中使用PHP编写PHP应用程序已有一段时间了。现在,我将在工作PC上分别安装PHP和Apache HTTP Server。我已经安装了PHP 5和最新的Apache。我去本地主机,看到它的工作原理! 现在,我添加了一个名为的文件,该文件显示: 但是在浏览器中,它仅显示纯文本。我有明确告诉它使用PHP 5的地方吗? 问题答案: 您需要将其添加到服务器配置中: 那是假设您已经正

  • 问题内容: 我目前正在决定要在其上构建科学计算产品的平台,并且正在决定在Core2 Quad CPU上使用C#,Java或带有Intel编译器的纯C语言。它主要是整数运算。 到目前为止,我的基准测试表明Java和C彼此差不多,并且.NET / C#落后大约5%,但是我的许多同事都声称经过适当的优化的.NET将在足够的时间上击败这两个方面。供JIT开展工作。 我一直以为JIT会在应用启动后的几分钟内

  • 问题内容: 下面是分别用和编码的简单过程(对于那些对此过程感到好奇的人,这是针对Euler项目5号问题的解决方案)。 我的问题是,下面的代码仅需9秒即可迭代,而代码完成则需要283秒(确切地说,在Python 3.4.3-64位上为283秒,在Python 2.7.9-32位上为329秒)。 到目前为止,我已经编码的两种类似的过程和与执行时间的差异,具有可比性。但是,这次,经过的时间之间存在极大的

  • 为什么使用 qmake 生成的比 cmake 生成的 dll 要大很多? 在Qt中,我们使用 qmake 和 cmake 分别创建一个项目,然后寻找Release运行程序,再使用Qt的打包工具,两者生成的dll文件大小相差很大,这是为什么?