You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中如何编码字节数组的Unicode补充字符?UTF-16LE异常排查

解决Java读取C# TCP服务器UTF-16LE字节时的字符解析问题

看起来你遇到的核心问题有两个:一是特定字符(比如"Ü")解析错误,二是补充字符无法正常处理。咱们一步步拆解解决:

一、先解决"Ü"解析错误的问题

首先核对字节对应关系:C#中Encoding.Unicode(即UTF-16LE)编码"Ü"时,输出的字节应该是0xDC 0x00(十进制220和0),对应Java有符号byte是-36 0。但你收到的是-3 -1(十进制253和255,即0xFD 0xFF),这组字节解析后是UTF-16LE的替换字符U+FFFD,说明你收到的字节和C#发送的不一致,大概率是字节读取不完整导致的。

1. 确保完整读取所有字节

Java的InputStream.read(byte[])不会保证填满整个数组,它返回实际读取的字节数。如果你的dataBytes是一次性读取的,很可能没拿到完整的服务器响应。正确的读取方式应该循环读取直到获取全部字节:

// 示例:读取指定长度的完整字节数组
public byte[] readFully(InputStream in, int length) throws IOException {
    byte[] buffer = new byte[length];
    int offset = 0;
    int bytesRead;
    while (offset < length && (bytesRead = in.read(buffer, offset, length - offset)) != -1) {
        offset += bytesRead;
    }
    if (offset != length) {
        throw new IOException("Failed to read all bytes: expected " + length + ", got " + offset);
    }
    return buffer;
}

在你的循环中处理textBytes时,也要确保读取到足够的字节:

short textLength = wrapped.getShort();
// 先检查ByteBuffer剩余字节是否足够
if (wrapped.remaining() < textLength) {
    throw new IllegalStateException("Not enough bytes for text (need " + textLength + ", have " + wrapped.remaining() + ")");
}
byte[] textBytes = new byte[textLength];
wrapped.get(textBytes);

2. 验证C#端的编码和发送字节

你可以在C#端打印发送的字节,和Java端接收的对比,确认数据一致性:

string test = "MÜNSTER";
byte[] bytes = Encoding.Unicode.GetBytes(test);
foreach (byte b in bytes) {
    Console.Write(b + " ");
}
// 预期输出:77 0 220 0 78 0 83 0 84 0 69 0 82 0

如果两端字节不一致,说明传输过程中存在编码转换或数据丢失,需要排查中间环节。

二、解决补充字符的处理问题

补充字符(比如😀,U+1F600)在UTF-16中由两个16位代码单元(4个字节)表示,Java的String类完全支持UTF-16代理对解析,只要你能完整读取到所有字节,new String(textBytes, StandardCharsets.UTF_16LE)就能正确解析。

举个例子:C#发送😀时,UTF-16LE字节是0x3D 0xD8 0x00 0xDE(十进制61, -40, 0, -34),Java读取后用UTF_16LE编码转换,就能正确显示表情符号。

三、对你现有代码的优化建议

  1. 用StandardCharsets.UTF_16LE代替字符串"UTF_16LE",避免拼写错误,同时更类型安全。
  2. 始终检查字节读取的完整性,避免因部分读取导致的乱码。
  3. 增加错误日志,方便排查字节不一致的问题。

优化后的核心代码片段:

ByteBuffer wrapped = ByteBuffer.wrap(dataBytes);
wrapped.order(ByteOrder.LITTLE_ENDIAN);
short noOfSites = wrapped.getShort();
for(int i = 0; i < noOfSites; i++){
    short siteNo = wrapped.getShort();
    short textLength = wrapped.getShort();
    
    if (wrapped.remaining() < textLength) {
        System.err.println("Error: Insufficient bytes for site " + siteNo);
        continue;
    }
    
    byte[] textBytes = new byte[textLength];
    wrapped.get(textBytes);
    
    // 打印字节用于调试
    System.out.print("Bytes for site " + siteNo + ": ");
    for(byte bite : textBytes){
        System.out.print(bite+" ");
    }
    System.out.println();
    
    String siteText = new String(textBytes, StandardCharsets.UTF_16LE);
    System.out.println(siteNo + ": " + siteText);
    siteList.add(new Site(siteNo, siteText));
    publishProgress(siteNo + " - " + siteText);
}

内容的提问来源于stack exchange,提问作者rm-green

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:02:23