Java 与 C# GZip 压缩

标签 java c# gzip gzipstream

知道为什么 Java 的 GZIPOutputStream 压缩字符串与我的 .NET 的 GZIP 压缩字符串不同吗?

Java 代码:

package com.company;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Base64;

public class Main {

    public static void main(String[] args) {
        String myValue = "<Grid type=\"mailing_activity_demo\"><ReturnFields><DataElement>mailing_id</DataElement></ReturnFields></Grid>";

        int length = myValue.length();

        byte[] compressionResult = null;

        try {
            compressionResult = MyUtils.compress(myValue);
        } catch (IOException e) {
            e.printStackTrace();
        }

        byte[] headerBytes = ByteBuffer.allocate(4).putInt(length).array();

        byte[] fullBytes = new byte[headerBytes.length + compressionResult.length];

        System.arraycopy(headerBytes, 0, fullBytes, 0, headerBytes.length);

        System.arraycopy(compressionResult, 0, fullBytes, headerBytes.length, compressionResult.length);

        String result = Base64.getEncoder().encodeToString(fullBytes);
        System.out.println((result));
    }
}




package com.company;

import javax.sound.sampled.AudioFormat;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.zip.GZIPOutputStream;

public class MyUtils
{

    private static Object BitConverter;

    public static byte[] compress(String data) throws IOException
    {
        ByteBuffer buffer = StandardCharsets.UTF_8.encode(data);
        System.out.println(buffer.array().length);
        System.out.println(data.length());
        ByteArrayOutputStream bos = new ByteArrayOutputStream(data.length());

        GZIPOutputStream gzip = new GZIPOutputStream(bos);

        gzip.write(data.getBytes());

        gzip.close();

        byte[] compressed = bos.toByteArray();

        bos.close();

        return compressed;

    }

}

我从上面得到的字符串是:

AAAAbB+LCAAAAAAAAP+zcS/KTFEoqSxItVXKTczMycxLj09MLsksyyypjE9Jzc1XsrMJSi0pLcpzy0zNSSm2s3FJLEl0zUnNTc0rsYPpyEyx0UcWt9FH1aMPssUOAKHavIJsAAAA

来自 .NET C# 代码:

    public static string CompressData(string data)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            byte[] plainBytes = Encoding.UTF8.GetBytes(data);

            using (GZipStream zipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
            {
                zipStream.Write(plainBytes, 0, plainBytes.Length);
            }

            memoryStream.Position = 0;

            byte[] compressedBytes = new byte[memoryStream.Length + CompressedMessageHeaderLength];

            Buffer.BlockCopy(
                BitConverter.GetBytes(plainBytes.Length),
                0,
                compressedBytes,
                0,
                CompressedMessageHeaderLength
            );

            // Add the header, which is the length of the compressed message.
            memoryStream.Read(compressedBytes, CompressedMessageHeaderLength, (int)memoryStream.Length);

            string compressedXml = Convert.ToBase64String(compressedBytes);

            return compressedXml;
        }
    }

压缩字符串:

bAAAAB+LCAAAAAAABACzcS/KTFEoqSxItVXKTczMycxLj09MLsksyyypjE9Jzc1XsrMJSi0pLcpzy0zNSSm2s3FJLEl0zUnNTc0rsYPpyEyx0UcWt9FH1aMPssUOAKHavIJsAAAA

知道我在 Java 代码中做错了什么吗?

最佳答案

为了补充 @MarcGravell 关于 GZip 编码差异的答案,值得注意的是,您的 header 字节似乎存在字节序问题,这会弄乱解码器。

您的 header 为 4 个字节,编码为 5 1/3 base64 字符。 .NET 版本输出 bAAAAB (前 4 个字节为 6c 00 00 00 ),而 Java 版本输出 AAAAbB (前 4 个字节为 00 00 00 6c )。事实上b在 A 的海洋中移动大约 5 个字符是您的第一个线索(A 代表 Base64 中的 000000),但对其进行解码会使问题变得显而易见。

.NET BitConverter使用机器架构的字节序,在 x86 上是小字节序(检查 BitConverter.IsLittleEndian )。 Java 的 ByteBuffer defaults to big-endian ,但是是可配置的。这解释了为什么一个写小端,另一个写大端。

您需要决定字节顺序,然后对齐两侧。您可以通过调用 .order(ByteBuffer.LITTLE_ENDIAN) 将 ByteBuffer 更改为使用小端字节序。 。在.NET中,您可以使用 BinaryPrimitives.WriteInt32BigEndian/BinaryPrimitives.WriteInt32LittleEndian如果您使用的是 .NET Core 2.1+,则以显式字节序写入,或使用 IPAddress.HostToNetworkOrder如果您陷入了较早的困境,则可以在必要时切换字节顺序(取决于 BitConverter.IsLittleEndian )。

关于Java 与 C# GZip 压缩,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67421608/

相关文章:

c# - 为什么我检测不到触摸屏?

c# - 使用 c# 在单个 xlsx 中读取多个 Excel 工作表

python - 在 python 中使用特定文本编码打开(可能压缩)文件的通用方法

java - 更新属性是否需要在主线程上进行?

java - ProJNA 数据类型映射

java - 校验和计算正确一次,然后在 Java 中使用 CRC32 后就不正确

c# - 如何在 Xamarin 中使用 UITextView 为 iOS 实现隐藏/显示密码样式体验?

带有 "Content-Encoding: gzip"的 Http 响应,但内容未压缩

python - 使用 python-requests 压缩请求体?

java - 如何在java中插入sql查询