使用C#解压被PHP的gzcompress()压缩的字符串

11

我正在使用C# 4.0查询一个Web服务,该服务提供了一个由PHP的gzcompress()压缩的字符串。现在我需要在C#中解压这个字符串。我尝试了几种方法,包括:

但是每次都会抛出"Missing Magic Number"异常。

有人能提供一些提示吗?

谢谢

编辑1:

我的最新尝试:

public static string Decompress(string compressed) {
    byte[] compressedBytes = Encoding.ASCII.GetBytes(compressed);
    MemoryStream mem = new MemoryStream(compressedBytes);
    GZipStream gzip = new GZipStream(mem, CompressionMode.Decompress);
    StreamReader reader = new StreamReader(gzip);
    return reader.ReadToEnd();
}

1
代码,代码,代码... 还有更多的代码。看不到问题就无法修复。 - Hogan
这是一个公共的 Web 服务还是你自己的?你确定你的 Web 服务的输出是正确的吗?你测试过使用 PHP 解压脚本的输出吗? - Erik van Brakel
你做错了。PHP的gzcompress函数不会返回ASCII字符串。 - dtb
那不是问题。以正确的方式进行操作(我已经从PHP中对其进行了base64编码,并在C#中进行了解码),真的没有帮助。 - Pieter van Ginkel
2个回答

11

好的,有一点帮助来自@boas.anthro.mnsu.edu

using (var mem = new MemoryStream())
{
    mem.Write(new byte[] { 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 }, 0, 8);
    mem.Write(inputBytes, 0, inputBytes.Length);

    mem.Position = 0;

    using (var gzip = new GZipStream(mem, CompressionMode.Decompress))
    using (var reader = new StreamReader(gzip))
    {
        Console.WriteLine(reader.ReadToEnd());
    }
}

关键在于添加一个神奇的头部。注意,这对SharpZipLib不起作用。它会抱怨没有页脚。然而,.NET解压器可以完美地工作。

还有一件事。关于ASCII.GetBytes()的评论是正确的:您的输入不是ASCII。我使用以下内容实现了此结果:

// From PHP:

<?php echo base64_encode(gzcompress("Hello world!")); ?>

// In C#:

string input = "eJzzSM3JyVcozy/KSVEEAB0JBF4=";

byte[] inputBytes = Convert.FromBase64String(input);

通过额外的base64编码和解码,这个代码可以完美运行。

如果你不能使用base64编码,你需要从PHP页面获取原始流。你可以使用GetResponseStream()来获取:

 var request = WebRequest.Create("http://localhost/page.php");

 using (var response = request.GetResponse())
 using (var mem = response.GetResponseStream())
 {
     // Decompression code from above.
 }

如果您可以控制PHP端,使用gzencode代替gzcompress将生成具有正确GZIP头和尾部的输出,而不是让您在C#端进行伪造。 - stevemegson
很遗憾,我无法控制PHP端。使用ASCII.GetBytes()还可以吗? - KitKat
不,问题是你从PHP页面获取数据的地方有误。我认为你将其作为字符串获取了。这是不正确的,你应该将其作为byte[](Memory)Stream获取。我已经在答案中添加了一个示例。如果你不知道如何做这个,或者示例不够用,请将你用于读取PHP页面的代码添加到文章中,我会给出建议,告诉你如何更改它。 - Pieter van Ginkel

1
我想在Peter的回答上做出延伸。PHP也可以使用Deflate算法进行压缩。在这种情况下,你应该使用DeflateStream而不是GZipStream,并删除前两个字节(HEX: 78 9C){{link1:从PHP实现处理的缓冲区无法使用DeflateStream} }。
 private static byte[] Decompress(byte[] data)
{
  using (var compressedStream = new MemoryStream(data.Skip(2).ToArray()))
  using (var zipStream = new DeflateStream(compressedStream, CompressionMode.Decompress))
  using (var resultStream = new MemoryStream())
  {
    zipStream.CopyTo(resultStream);
    return resultStream.ToArray();
  }
}

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