Java 对比 C# GZip 压缩
Java vs C# GZip Compression
知道为什么 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+LCAAAAAAAAAP+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 上是 little-endian(检查 BitConverter.IsLittleEndian
)。 Java 的 ByteBuffer
defaults to big-endian,但可配置。这就解释了为什么一个写 little-endian,另一个写 big-endian.
您需要确定字节顺序,然后对齐两端。您可以通过调用 .order(ByteBuffer.LITTLE_ENDIAN)
将 ByteBuffer 更改为使用 little-endian。在 .NET 中,如果您使用的是 .NET Core 2.1+,则可以使用 BinaryPrimitives.WriteInt32BigEndian
/ BinaryPrimitives.WriteInt32LittleEndian
以显式字节顺序编写,或者在必要时使用 IPAddress.HostToNetworkOrder
切换字节顺序(取决于BitConverter.IsLittleEndian
) 如果你之前卡住了。
知道为什么 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+LCAAAAAAAAAP+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 上是 little-endian(检查 BitConverter.IsLittleEndian
)。 Java 的 ByteBuffer
defaults to big-endian,但可配置。这就解释了为什么一个写 little-endian,另一个写 big-endian.
您需要确定字节顺序,然后对齐两端。您可以通过调用 .order(ByteBuffer.LITTLE_ENDIAN)
将 ByteBuffer 更改为使用 little-endian。在 .NET 中,如果您使用的是 .NET Core 2.1+,则可以使用 BinaryPrimitives.WriteInt32BigEndian
/ BinaryPrimitives.WriteInt32LittleEndian
以显式字节顺序编写,或者在必要时使用 IPAddress.HostToNetworkOrder
切换字节顺序(取决于BitConverter.IsLittleEndian
) 如果你之前卡住了。