C#: 压缩 XML 和 JavaScript 压缩的结果不同

4

我正在尝试在C#中压缩一个XML并将其编码为Base64。我尝试使用DeflateStream和GZipStream,但似乎与在node库中执行不同。


以下是node代码和C#代码:

//zlib = require('zlib');
zlib.deflateRaw(xml, (function(_this) {
      return function(err, deflated) {
             return deflated.toString('base64');
      }
} 

C# DeflateStream

 private static byte[] Deflate(String str)
    {
      using (MemoryStream output = new MemoryStream())
      {
        using (DeflateStream gzip =
          new DeflateStream(output, CompressionMode.Compress))
        {
          using (StreamWriter writer =
            new StreamWriter(gzip, System.Text.Encoding.UTF8))
          {
            writer.Write(str);
          }
        }

        return output.ToArray();
      }
    }

C#的GZipStream

public static byte[] Zip(string str)
{
      var bytes = Encoding.UTF8.GetBytes(str);

      using (var msi = new MemoryStream(bytes))
      using (var mso = new MemoryStream())
      {
        using (var gs = new GZipStream(mso, CompressionMode.Compress))
        {
          //msi.CopyTo(gs);
          CopyTo(msi, gs);
        }

        return mso.ToArray();
      }
 }

C# Base64编码:

private static string Base64Encode(byte[] textBytes)
{
   return System.Convert.ToBase64String(textBytes);
} 

我有所遗漏吗?

更新

我找到了一个可以使用的示例。通过使用这个示例,我也可以在Node中对其进行解码。

 var bytes = Encoding.UTF8.GetBytes(stringToDeflate);
  using (var output = new MemoryStream())
  {
    using (var zip = new DeflateStream(output, CompressionMode.Compress))
    {
      zip.Write(bytes, 0, bytes.Length);
    }
    var base64 = Convert.ToBase64String(output.ToArray());
  }

更新 2(有效代码 - 供未来搜索者使用)

private static string DeflateAndEncode(string str)
    {
      var bytes = Encoding.UTF8.GetBytes(str);
      using (var output = new MemoryStream())
      {
        using (var zip = new DeflateStream(output, CompressionMode.Compress))
        {
          zip.Write(bytes, 0, bytes.Length);
        }
        var base64 = Convert.ToBase64String(output.ToArray());

        return base64;
      }
    }

    private static string DecodeAndInflate(string str)
    {
      var utf8 = Encoding.UTF8;
      var bytes = Convert.FromBase64String(str);
      using (var output = new MemoryStream())
      {
        using (var input = new MemoryStream(bytes))
        {
          using (var unzip = new DeflateStream(input, CompressionMode.Decompress))
          {
            unzip.CopyTo(output, bytes.Length);
            unzip.Close();
          }
          return utf8.GetString(output.ToArray());
        }
      }
    }

很可能是编码问题。你可以尝试使用new StreamWriter(gzip)而不是UTF-8编码吗? - Freggar
@bommelding 在 Node 输出中有 513 个字符,在 C# 实现中有 537 个字符。 - Andrew
添加了一个似乎有效的更新。 - Andrew
@bommelding 我发现一个区别(但我不确定是否有影响),就是工作的代码没有使用 StreamWriter。 - Andrew
public static void CopyTo(Stream src, Stream dest) { byte[] bytes = new byte[4096]; int cnt; while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) { dest.Write(bytes, 0, cnt); } } - Andrew
1个回答

0

在C#和Node.js之间,用于base-64编码的字符是不同的。

C#使用以下字符

从零开始按升序排列的base-64数字是大写字母"A"到"Z"、小写字母"a"到"z"、数字"0"到"9"和符号"+"和"/"。值为空的字符"="用于尾部填充。

Node.js使用RFC4648第5节中指定的"URL和文件名安全的Base 64字母表"

A-Z, a-z, 0-9, - (minus), _ (underscore)
Trailing padding uses '='

所以你想做的事情是行不通的。

你可以尝试将 C# 编码中的 _- 分别替换为 +/,然后再将其转换为 Node.js 编码或相反,最后对数据进行 base64 解码来修复它。


但这并不考虑长度的差异。 - bommelding
@Matthew Watson,这个更改应该在原始文本中进行吗?否则我会得到一个压缩后的字节数组。 - Andrew
你能给出哪些字符串不同的例子吗?我尝试了 "testcode!!!/+_-",但得到了预期的(相等)结果。这是我的 NodeJSFiddler 和我的 C#.NET Fiddler - Freggar
@Freggar,你的测试代码中的base64输入不包含不同的字符。尝试使用这个二进制数据:Enumerable.Range(0, 255).Select(x => (byte)x).ToArray() - Matthew Watson
奇怪,我仍然得到相同的结果(我更新了我的 Fiddler 链接) - Freggar
@Freggar 嗯,确实很奇怪 - 根据我提供的规格说明,Node.js使用“_”字符进行base-64编码(而.Net不使用该字符)。 - Matthew Watson

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