我觉得答案很明显,但假设我在 C# 中有以下内容
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
// Write some floats, bytes, and uints
// Convert.ToBase64String this stuff from ms.ToArray
}
}
以及 Java 中的以下内容(好吧,它是 Scala,但使用 Java 库):
val byteStream = new ByteArrayOutputStream()
val outStream = new DataOutputStream(byteStream)
// Write some floats, bytes, and longs where the uints were using
// writeFloat, writeByte, and writeLong. .NET has an overloaded
// function that takes whatever.
// Base64.getEncoder.encodeToString byteStream.toByteArray
我得到完全不同的 Base 64 字符串。他们在这里做了什么不同的事情?我需要 Java 输出来匹配 .NET 输出。我认为它存在某种字节排序问题,但我没有使用 ByteBuffer
运气好。来纠正这个问题。
Java:
PczMzT3MzM0/gAAAPczMzQAAAAAAAAAAAAAAAD3MzM0/gAAAAQAAAABRn8XzAAAAAAAAAAEAAAAAAAAAAQ==
C#(带有未知 = 符号,因为我们出于某种原因将其砍掉):
zczMPc3MzD0AAIA/zczMPQAAAAAAAAAAAAAAAM3MzD0AAIA/AfPFn1EBAAAAAQAAAA
我真的觉得它是字节排序的,这就是为什么我尝试使用 ByteBuffer
在Java代码中,order方法,改变顺序但我没有成功。
为了进一步说明,Java 代码在 x86_64 CentOS Java 7 上运行,.NET 在 x86_64 Windows Server 2008 .NET 4 上运行。这些值来自 Protobuf 对象,因此我认为它们应该是非常跨平台的。从数字上讲,无论我输入什么,至少当我至少编写这三种数据类型时,数据都是相同且一致的。唯一显着的区别是 Java 中缺少无符号类型,并且可能存在二进制表示差异,这是我最初试图解决的问题,但我似乎无法弄清楚。
正如我所说。使用其他格式不是一种选择。我需要从 java 编写的二进制数据,然后进行 Base 64 编码,以产生与 .NET 相同的结果。序列化选择不是一个选项。必须是这样。我需要一种资源来帮助将它们整合在一起,无论这是否意味着字节数据的二进制操作。我需要对数据类型进行一些解释,因为我进行了大量搜索,但没有找到解释如何执行此操作或真正差异是什么的资源,以便我可以实现我决定在这里询问的解决方案。
最佳答案
主要问题是 C# 的 BinaryWriter
首先写入数据类型的低字节,而 Java 的 DataOutputStream
首先写入高字节。
此外,当您写入 .NET 无符号整数时,会写入 4 个字节。但是当您编写 Java long
时,它会写入 8 个字节。这就是另一个区别。
但是,一旦您了解了差异,将它们修复为匹配实际上并不难。以下是 2 个代码片段,一个使用 C#,另一个使用 Java,它们编码相同的信息并输出相同的 Base64
编码字符串。就我而言,我选择重写 Java 编写 float
和 long
的方式。
.NET 代码示例
static void Main(string[] args)
{
using (MemoryStream ms = new MemoryStream())
{
using (BinaryWriter bw = new BinaryWriter(ms))
{
// floats
bw.Write(-456.678f);
bw.Write(0f);
bw.Write(float.MaxValue);
// bytes
bw.Write((byte)0);
bw.Write((byte)120);
bw.Write((byte)255);
// uints
bw.Write(0U);
bw.Write(65000U);
bw.Write(4294967295U);
}
var base64String = Convert.ToBase64String(ms.ToArray());
Console.WriteLine(base64String);
}
}
Java 代码示例
public static void main(String[] args) throws Exception {
try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream()) {
try (DataOutputStream outStream = new DataOutputStream(byteStream)) {
// floats
writeFloat(-456.678f, outStream);
writeFloat(0f, outStream);
writeFloat(Float.MAX_VALUE, outStream);
// bytes
outStream.writeByte(0);
outStream.writeByte(120);
outStream.writeByte(255);
// longs (uints)
writeUint(0L, outStream);
writeUint(65000L, outStream);
writeUint(4294967295L, outStream);
}
String base64String = Base64.getEncoder().encodeToString(byteStream.toByteArray());
System.out.println(base64String);
}
}
private static void writeFloat(float f, DataOutputStream stream) throws Exception {
int val = Float.floatToIntBits(f);
stream.writeByte(val & 0xFF);
stream.writeByte((val >>> 8) & 0xFF);
stream.writeByte((val >>> 16) & 0xFF);
stream.writeByte((val >>> 24) & 0xFF);
}
private static void writeUint(long val, DataOutputStream stream) throws Exception {
stream.writeByte((int) (val & 0xFF));
stream.writeByte((int) ((val >>> 8) & 0xFF));
stream.writeByte((int) ((val >>> 16) & 0xFF));
stream.writeByte((int) ((val >>> 24) & 0xFF));
}
两个样本的输出
yVbkwwAAAAD//39/AHj/AAAAAOj9AAD/////
确保使用 float
类型测试边缘情况,并在必要时进行调整。如果这对您很重要,我希望像 NaN
这样的有趣值会导致差异,但也许您不关心这一点。否则,我希望它能正常工作。
关于java - Java 和 C# 之间的 Base64 和二进制流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32771605/