GZipStream 机器依赖问题

15

我在.NET 4.0中遇到了一些奇怪的机器/操作系统相关的GZipStream行为。以下是相关代码:

public static string Compress(string input) {
    using(var ms = new MemoryStream(Encoding.UTF8.GetBytes(input)))
    using(var os = new MemoryStream()) {
        using(var gz = new GZipStream(os,CompressionMode.Compress,true)) {
            ms.CopyTo(gz);
        }
        return string.Join("",os.ToArray().Select(b=>b.ToString("X2")));
    }
}

运行Compress("freek")会给我:

1F8B08000000000004004B2B4A4DCD06001E33909D05000000

在Windows 7上

1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22CEEB3C7FFBFF040000FFFF1E33909D05000000

在Windows Server 2008R2上我有两台64位的机器,我希望得到相同的结果。

当我解压缩任何一个结果时,两台机器都会给出正确的结果。我已经发现在 W7 上 ms.Length == 25,而在 W2K8R2 上 ms.Length==128,但不知道原因。

这是怎么回事?


1
这同样适用于MemoryStream。尝试过没有gzip吗? - H H
@Henk 为什么你会这样想呢?是MemoryStream在W2K8R2上补充了另外的123个字节吗? - Freek
你是否在任务管理器中检查了两台机器是否都显示为64位进程?你的构建设置如何? - weismat
1
128字节看起来像是流的块大小。压缩更有可能使用128位。 - H H
无损压缩保证在压缩解压循环后恢复相同的结果,但我看不出为什么期望压缩形式总是相同。你为什么期望答案是相同的? - J D
5个回答

18

据宣布,.NET 4.5 Beta包括ZIP压缩改进以减小文件大小

从.NET Framework 4.5 RC开始,DeflateStream类使用zlib库进行压缩。因此,在大多数情况下,它提供了更好的压缩算法和更小的压缩文件,而不是.NET Framework早期版本中提供的压缩效果。

您的Win7机器上是否安装了.NET 4.5+?


5
由于我们在运行混合的4.0/4.5版本服务器,并在将内容压缩后放入Redis缓存的唯一集合之前进行了gzip处理,这个问题在Stack Overflow上困扰了我们。如果您依赖于相同的压缩结果(例如从集合中删除项目),请注意不要在4.0和4.5服务器的混合环境下运行。 - Nick Craver
太好了!现在我知道如何在客户面试期间解释为什么我的程序无法工作了! - VMAtm

5

看起来.NET 4.5中DeflateStream使用的算法发生了变化

从.NET Framework 4.5 Beta开始,DeflateStream类使用zlib库进行压缩。因此,在大多数情况下,它提供了更好的压缩算法和更小的压缩文件,比早期版本的.NET Framework提供的要好。

由于我安装了4.5版本,这导致了问题的出现。


2
我不认为这是一个破坏性的变化。它只是一个性能改进。应用程序对此API的结果除了符合gzip规范之外,不应该有任何期望。 - Robert Levy
这是一个重大变化,但比以前版本的重大变化更糟糕。.NET 4.5替换了.NET 4.0,这意味着在同一台计算机上安装使用.NET 4.5的应用程序可能会破坏已经安装的使用.NET 4.0的应用程序,但将开始使用.NET 4.5。 - zumalifeguard

1

我在我的Windows 7 64位机器上运行了你的代码,得到了以下结果,与你的Win2k8SP2相同:

1F8B0800000000000400ECBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F229ED579FEF6FF090000FFFF1A1C515C05000000

基本上,我认为结果与机器的字长有关。也就是说,你的windows-7机器可能是32位的?
注意:我为你的字符串编写了一个小型解压程序,我必须确认它们确实可以很好地解压缩。我在32位和64位上都运行了我的版本,结果是相同的。唯一可能的区别是:不同的运行时间?
编辑:
不同的运行时间?
显然,正如Henk Holterman在下面建议的,以及他的答案Robert Levy所规范的,这确实是这里的非显而易见的情况。

两者都是64位的,忘记提到了。 - Freek
你正在运行哪个版本的 Visual Studio? - Freek
我得到了与Abel相同的输出。我们确定VS版本是相同的吗? - user7116
1
@Henk,看起来这似乎是问题所在,正在验证中。根据MSDN:从.NET Framework 4.5 Beta开始,DeflateStream类使用zlib库进行压缩。因此,在大多数情况下,它提供了更好的压缩算法和更小的压缩文件,比早期版本的.NET Framework提供的要好。 - Freek

1

Abel答案相反,我得到了结果

1F8B08000000000004004B2B4A4DCD06001E33909D05000000

我在我的Windows 7 x64 Ultimate SP1上遇到了这个问题。也许你的某个框中缺少了.NET Framework更新?我的mscorlib.dll版本是4.0.30319.17379。

预计时间:如果我重新定位到.NET 2(并将.NET 4特定结构更改为它们的.NET 2等效结构),我确实得到了结果。

1F8B0800000000000400EDBD07601C499625262F6DCA7B7F4AF54AD7E074A10880601324D8904010ECC188CDE692EC1D69472329AB2A81CA6556655D661640CCED9DBCF7DE7BEFBDF7DE7BEFBDF7BA3B9D4E27F7DFFF3F5C6664016CF6CE4ADAC99E2180AAC81F3F7E7C1F3F22CEEB3C7FFBFF001E33909D05000000

在同一台机器/操作系统上。


我怀疑是因为SP1更新的缘故。我正在进行测试。 - Freek
实际上,在这个盒子上我有。我看到了你关于4.5版本中增加的可压缩性的评论,那确实是正中要害。很好的发现! - Jesse C. Slicer

0
我怀疑其中一个操作系统是32位的,而另一个是64位的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接