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

Java中ByteArray转String时出现异常字符问题

解决Java Socket传输双字节填充字节数组转String乱码问题

嘿,这个问题我之前帮朋友处理过类似的,你踩的坑主要是两个:编码不匹配和截断时破坏了双字节字符的结构,我给你一步步拆解怎么搞定:

先搞懂问题根源

你定义的byte[40]存20个字符,说明每个字符占2字节——这明显是双字节编码(比如Java默认的UTF-16,因为Java里char就是UTF-16编码)。但你转String的时候,大概率用了单字节编码(比如UTF-8),或者截断0的时候切到了某个字符的一半,自然就出现异常字符了。

具体解决步骤

1. 确认原数组的编码

首先得和原字符串转byte数组时的编码保持一致。根据你的描述,几乎可以肯定是UTF-16(毕竟20个字符×2字节=40字节,完美匹配)。如果是其他双字节编码(比如GB2312),后面转码时对应调整就行。

2. 正确截断无效的0填充

因为是双字节编码,所以无效填充是连续的两个0字节(0x00 0x00),不是单个0。你得找到第一个连续双字节0的位置,然后截断到这个位置之前,确保有效字节长度是2的倍数——不然切到字符中间肯定乱码。

示例代码:

// 假设接收的字节数组是receivedBytes
int validLength = 0;
// 按双字节遍历,别踩单字节的坑
for (int i = 0; i < receivedBytes.length; i += 2) {
    // 检查当前双字节是不是填充的0
    if (i + 1 < receivedBytes.length && receivedBytes[i] == 0 && receivedBytes[i+1] == 0) {
        break;
    }
    validLength += 2;
}
// 截取有效字节,长度肯定是2的倍数
byte[] validBytes = Arrays.copyOf(receivedBytes, validLength);

3. 用正确编码转成String

用和原数组一致的编码(比如UTF-16)把有效字节转成String:

// Java默认的UTF-16是大端(UTF-16BE),如果原数组是小端(UTF-16LE),要指定StandardCharsets.UTF_16LE
String filePath = new String(validBytes, StandardCharsets.UTF_16);

4. 处理特殊控制字符(可选)

像你示例里的0x03这种,是ASCII控制字符,转成String后会显示异常,你可以过滤掉:

// 过滤所有ASCII控制字符,保留正常可见字符
filePath = filePath.replaceAll("\\p{Cntrl}", "");

完整可运行示例

import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class SocketPathDecoder {
    public static void main(String[] args) {
        // 模拟你接收的字节数组
        byte[] receivedBytes = {116, 111, 117, 99, 104, 50, 46, 116, 120, 116, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        
        // 1. 计算有效双字节长度
        int validLength = 0;
        for (int i = 0; i < receivedBytes.length; i += 2) {
            if (i + 1 < receivedBytes.length && receivedBytes[i] == 0 && receivedBytes[i+1] == 0) {
                break;
            }
            validLength += 2;
        }
        byte[] validBytes = Arrays.copyOf(receivedBytes, validLength);
        
        // 2. 转成字符串
        String filePath = new String(validBytes, StandardCharsets.UTF_16);
        
        // 3. 过滤控制字符
        filePath = filePath.replaceAll("\\p{Cntrl}", "");
        
        System.out.println("处理后的文件路径:" + filePath);
    }
}

关键提醒

  • 编码必须完全匹配!原数组用UTF-16存,转String就必须用UTF-16,差一个字都会乱码。
  • 双字节编码下,截断长度必须是2的倍数,绝对不能切到单个字节。
  • 如果你的场景是单字节编码(比如UTF-8),那40字节应该能存40个ASCII字符,和你说的“20个字符”矛盾,所以优先考虑双字节编码。

内容的提问来源于stack exchange,提问作者Carrein

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:23:39