记一次字符串传输设备的坑
本文主要涉及到可变长度编码UTF-8的知识
- 问题描述
char[]data = new char[]{48,48,48,48,48,48,252};
// 起初,我们使用字符串传输该值,000000ü
this.sendMessage(String.valueOf(data).getBytes());
// 设备端接收到的值(PS:设备端使用单字节解析,单字节转为16进制)
61 61 61 61 61 61 C3 BC
// 然而25216进制值应该是FC,正确的值应该如下:
61 61 61 61 61 61 FC
- 问题分析
// 数组转为字符串 000000ü
// 字符串默认使用UTF-8编码
// 发送时字符串使用 getBytes() 获得字符数组发送
# 查找资料得知UTF-8的编码格式
UTF8是可变长。有的文字是1个字节存储的,有的文字是2个字节存储的,
还有3个字节存储的,还有4个字节存储的。
最后集合起来就是一共有一到四字节四种变长的编码。
一字节:0*******
两字节:110*****,10******
三字节:1110****,10******,10******
四字节:11110***,10******,10******,10******
就是这四种情况。相信你已经知道我们怎么来判断一个字是几字节的了。
如果是以0开头的,那么他就是一个1字节编码,取到它一字节的数据去一字节表中找就OK了。
如果是以110开头的,那么它就是一个2字节编码,取到它两字节的数据去两字节表中找就OK了,
而且它的第二个字节一定要是10开头,不然就是乱码了。
后面类推。
核心之处就是:
把0,110,1110,11110这4种比特用在不同的位置而区分开不同长度的编码.
把10这个比特用来连接多字节字符之间的多个字节。
# 后经该网站 http://www.mytju.com/classcode/tools/encode_utf8.asp 转换得知 ü 的编码值
字符 编码10进制 编码16进制 Unicode编码10进制 Unicode编码16进制
ü 50108 C3BC 252 FC
|字符| 编码10进制 | 编码16进制 | Unicode编码10进制 | Unicode编码16进制 |
| ---| --------- | ---------- | ----------------- | ------------------ |
| ü | 50108 | C3BC | 252 | FC |
- 问题呈现
故得知:是由于取值128-255的char值在使用UTF-8编码转为字符串时,其252会转为ü,
在字符串转为数组时用2个字节表示
- 解决方式
int ori=200;
System.out.println("原始byte值:"+ori);
Byte b=(byte)ori;
System.out.println("java中byte值:"+b);
Integer i=b.intValue();
System.out.println("转换后的int值:"+i);
System.out.println("存储的2进制值:"+Integer.toBinaryString(i));
Integer i_trans=i&0xFF;
System.out.println("&0xFF后的:"+i_trans);
输出如下:
原始byte值:200
java中byte值:-56
转换后的int值:-56
存储的2进制值:11111111111111111111111111001000
200
- 使用数组时
char[]data = new char[]{48,48,48,48,48,48,252};
byte[]dataBytes = new byte[data.lenth];
for(int i = 0; i < data.length; i++){
int dataVal = data[i];
dataBytes[i] = (byte)dataVal;
}
sendMessage(dataBytes);