Java 和 C# 的 deflate 函数的区别

Cyp*_*ius 8 c# java scala zio

我有 2 个用 C# 和 Scala 编写的 deflate 函数,当使用相同的输入运行时,返回的字节数组在前导字节和尾随字节中存在差异(中间字节之间的差异是由无符号/有符号字节机制预期的) C# 和 Scala)。

\n

Scala 中的 Deflate 函数:

\n
import java.io.ByteArrayOutputStream\nimport java.util.zip.{Deflater, DeflaterOutputStream}\n\nimport zio._\n\n\nobject ZDeflater {\n  val deflater = ZManaged.makeEffectTotal(new Deflater(Deflater.DEFLATED, true))(_.end)\n\n  val buffer = ZManaged.fromAutoCloseable(ZIO.succeed(new ByteArrayOutputStream()))\n\n  val stream = for {\n    d <- deflater\n    b <- buffer\n    s <- ZManaged.fromAutoCloseable(ZIO.succeed(new DeflaterOutputStream(b, d, true)))\n  } yield (b, s)\n\n  def deflate(input: Array[Byte]): RIO[blocking.Blocking, Array[Byte]] = stream.use { case (buffer, stream) =>\n    for {\n      ()    <- blocking.effectBlocking(stream.write(input))\n      ()    <- blocking.effectBlocking(stream.flush())\n      result = buffer.toByteArray\n    } yield result\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

C# 中的放气函数:

\n
private static byte[] Deflate(byte[] uncompressedBytes)\n{\n    using (var output = new MemoryStream())\n    {\n        using (var zip = new DeflateStream(output, CompressionMode.Compress, true))\n        {\n            zip.Write(uncompressedBytes, 0, uncompressedBytes.Length);\n        }\n\n        return output.ToArray();\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

放气后的输出:\nScala:

\n
ZDeflater.deflate(data.getBytes(StandardCharsets.UTF_8))\n\n124, -111, \xe2\x80\xa6, 126, 1, 0, 0, -1, -1\n
Run Code Online (Sandbox Code Playgroud)\n

C#:

\n
Deflate(Encoding.UTF8.GetBytes(data))\n125, 145, \xe2\x80\xa6, 126, 1\n
Run Code Online (Sandbox Code Playgroud)\n

有谁知道是什么原因导致第一个和最后一个字节之间的差异?你的任何假设对我都非常有帮助。谢谢一堆

\n

P/s:我们遇到了一个问题,C# 的 Deflate 输出适用于特定的第三部分,而 Scala 的输出则不然。所以我想弄清楚如何使 Scala 的输出与 C# 的输出相同

\n

rmu*_*nge 7

如此处所述,Java 的Deflater类将字节序列压缩为ZLIB 压缩数据格式。ZLIB 数据格式以DEFLATE 数据格式包装压缩数据,并在压缩数据后带有标头和 ADLER-32 校验和。

Microsoft 的DeflateStream文档对于确切的数据格式不准确。但它实际上以原始 DEFLATE 数据格式而不是 ZLIB 格式(dotnet-2236)生成数据。有了它,它的输出也与 HTTP 的“deflate”传输编码不兼容,后者实际上引用了 ZLIB 数据格式而不是 DEFLATE 数据格式(RFC-2616)。

但是现在如何使用 Scala 和 C# 获得相同的输出呢?

A) 使用 Scala 也以原始 DEFLATE 格式写入数据

该类Deflater有一个带有参数的重载构造nowrap函数,允许省略标头和校验和。将此参数设置为true将产生原始 DEFLATE 数据格式的压缩数据。如果您还计划在 Java 中反序列化数据,请Inflater仔细阅读构造函数的 Javadoc。

B) 使用 C# 也以 ZLIB 格式写入数据(推荐)

使用 .NET 的ZLibStream类或任何第三方库代替该类Deflater,以 ZLIB 格式序列化数据。

C) 使用 GZIP 格式代替

GZIP 格式与 ZLIB 相当,但使用不同的标头和不同的校验和。.NET 和 Java 都为其提供了显式流类。尽管 ZLIB 的校验和计算比 GZIP 性能更好并且产生的标头更小,但后者更常见(尤其是在 Web 中)。GZIP 受欢迎的主要原因是,Microsoft 始终难以区分原始 DEFLATE 和 ZLIB resp.HTTP 的deflate传输编码(请参阅 ZLIB 的FAQ-39;-)