Java与C#中的UTF-16编码不同
本文关键字:编码 UTF-16 中的 Java | 更新日期: 2023-09-27 18:26:13
在C#和Java中将字符串转换为字节时,我遇到了不同的结果。
C#:
byte[] byteArray = Encoding.Unicode.GetBytes ("chess ¾");
for (int i = 0; i < byteArray.Length; i++)
System.Diagnostics.Debug.Write (" " + byteArray[i]);
System.Diagnostics.Debug.WriteLine("");
System.Diagnostics.Debug.WriteLine(Encoding.Unicode.GetString(byteArray));
显示:
99 0 104 0 101 0 115 0 115 0 32 0 190 0
chess ¾
Java:
byte[] byteArray = "chess ¾".getBytes("UTF-16LE");
for (int i = 0; i < byteArray.length; i++)
System.out.print(" " + (byteArray[i]<0?(-byteArray[i]+128):byteArray[i]));
System.out.println("");
System.out.println(new String(byteAppName,"UTF-16LE"));
显示:
99 0 104 0 101 0 115 0 115 0 32 0 194 0
chess ¾
请注意,字节数组中倒数第二个值是不同的!我的目标是加密这些数据,并能够从C#或Java中读取它。这种差异似乎是一个障碍。
顺便说一句,在我学会使用Unicode(C#)/UTF-16LE(Java)之前,我使用的是UTF-8。。。
C#:byte[] byteArray = Encoding.UTF8.GetBytes ("chess ¾");
显示:99 104 101 115 115 32 194 190
Java:byteArray = appName.getBytes("UTF-8");
显示:99 104 101 115 115 32 190 194
奇怪的是,这导致倒数第二个字节和最后一个字节被翻转。
最后,¾
的Unicode是十进制190(http://www.fileformat.info/info/unicode/char/BE/index.htm),不是十进制194(?)(http://www.fileformat.info/info/unicode/char/00c2/index.htm)。
如有任何帮助,我们将不胜感激。
问题不在于编码,而在于打印结果的方式,您使用byteArray[i] < 0 ? (-byteArray[i] + 128) : byteArray[i]
从字节转换为整数,这会给您带来不正确的结果,请使用byteArray[i] & 0xFF
等其他方法。使用以下poc:比较两种转换
String encoding = "UTF-16LE";
byte[] byteArray = "chess ¾".getBytes(encoding);
for (int i = 0; i < byteArray.length; i++) {
// your conversion
System.out.print(" " + (byteArray[i] < 0 ? (-byteArray[i] + 128) : byteArray[i]));
// a more appropriate one
System.out.print("(" + (byteArray[i] & 0xFF) + ") ");
}
System.out.println("");
System.out.println(new String(byteArray, encoding));
我的猜测。
UTF-16LE表示字符占用2或4个字节。
看看这个,向下滚动到3/4。你会看到190和194(1100001010111110)-这是你需要编码符号的两个字节,它显然被称为";VULGAR分数四分之三";。
当您创建byte[]
时,数组只能存储1个字节,而不能存储2个字节,因此您将错过一个字节。在C#中,您会错过194,而在Java中,您将错过190。
原因是endianness。看看这个答案。
在Java中,getBytes("UTF-16")返回一个big-endian表示。
C#的System.Text.Encoding.Unicode.GetBytes返回一个小的endian表示。
然而,在Java中,getBytes("UTF-16LE")
根据这个以小端序返回,这就是您正在使用的。
我现在有点怀疑。
我需要更多地思考您在Java中到底在做什么。还不确定如何解决。