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
相关产品推荐
相关产品推荐

