发布于2020-11-19 20:54 阅读(1236) 评论(0) 点赞(14) 收藏(0)
底层json由于很长,所以分成多次发送,我每次接受到一部分就new String(),最后再把多个String拼接成一个json数组,刚开始系统运行良好,后来莫名其妙就会出现乱码,最后发现是new String()出现的问题,这里做一个模拟;
1、json数组
- {
- "a": "我们来自不同的世界"
- }
2、解析通过toBytes之后的数组
- String a1 = "{\n" +
- " \"a\": \"我们来自不同的世界\"\n" +
- "}";
- System.out.println(Arrays.toString(a1.getBytes()));
-
-
- 输出之后的数组
- [123, 10, 32, 32, 34, 97, 34, 58, 32, 34, -26, -120, -111, -28, -69, -84, -26, -99, -91, -24, -121, -86, -28, -72, -115, -27, -112, -116, -25, -102,
- -124, -28, -72, -106, -25, -107, -116, 34, 10, 125]
3、为了模拟我把这个数组分成两个部分,然后通过new String拼接
- public static void main(String[] args) {
- // String a1 = "{\n" +
- // " \"a\": \"我们来自不同的世界\"\n" +
- // "}";
- // System.out.println(Arrays.toString(a1.getBytes()));
- byte[] a = {123, 10, 32, 32, 34, 97, 34, 58, 32, 34, -26, -120, -111, -28, -69, -84, -26, -99, -91, -24, -121, -86, -28, -72, -115, -27, -112, -116, -25, -102};
- byte[] b = {-124, -28, -72, -106, -25, -107, -116, 34, 10, 125};
- System.out.println(new String(a)+new String(b));
- }
输出的结果:
- {
- "a": "我们来自不同��世界"
- }
当然,如果运气好,刚好接收的字节没有汉字拆分,这种组合是没有问题的,如下
- public static void main(String[] args) {
- // String a1 = "{\n" +
- // " \"a\": \"我们来自不同的世界\"\n" +
- // "}";
- // System.out.println(Arrays.toString(a1.getBytes()));
- byte[] a = {123, 10, 32, 32, 34, 97, 34, 58, 32, 34, -26, -120, -111, -28, -69, -84, -26, -99, -91, -24, -121, -86, -28, -72, -115, -27, -112, -116, -25, -102,-124};
- byte[] b = { -28, -72, -106, -25, -107, -116, 34, 10, 125};
- System.out.println(new String(a)+new String(b));
- }
结果
- {
- "a": "我们来自不同的世界"
- }
原因解析
字符串被解析成字节数组的时候,我的intellij默认使用的是UTF-8编码,所以一个汉字会被编码成三个字节,此文中的‘的’汉字编码为: -25, -102,-124,
而且我们通过new String发现,这三个字节就是汉字‘的’
- byte[] c = { -25, -102,-124};
- System.out.println(new String(c));
- 输出:的
如果按照我们第一种乱码的分数组方式,会发现第一个字节数组a中包含-25,-102,第二个数组b包含-124,在new String()的时候,默认还是使用UTF8编码,因为不认识-25,-102和-124,所以变成两个乱码��
解决方法
1、将数组a和数组b组合成一个数组之后,再使用new String()处理
2、因为我是一次只能接收一块,然后使用redis临时储藏这一块数据,所以我把收到的数据都转换成为了16进制字符串,最后再把16进制字符串从redis获取,全部合并,再转换成json字符串,也能解决问题
- HexUtils.encodeHexStr(blockData)
- new String(HexUtils.decodeHex(allData.toCharArray()))
工具类如下,很久以前在博客上看到的,不晓得是那一片博客了
- public class HexUtils {
- /**
- * 用于建立十六进制字符的输出的小写字符数组
- */
- private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
- /**
- * 用于建立十六进制字符的输出的大写字符数组
- */
- private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
- '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
-
- /**
- * 将字节数组转换为十六进制字符数组
- *
- * @param data
- * byte[]
- * @return 十六进制char[]
- */
- public static char[] encodeHex(byte[] data) {
- return encodeHex(data, true);
- }
-
- /**
- * 将字节数组转换为十六进制字符数组
- *
- * @param data
- * byte[]
- * @param toLowerCase
- * <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
- * @return 十六进制char[]
- */
- public static char[] encodeHex(byte[] data, boolean toLowerCase) {
- return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
- }
-
- /**
- * 将字节数组转换为十六进制字符数组
- *
- * @param data
- * byte[]
- * @param toDigits
- * 用于控制输出的char[]
- * @return 十六进制char[]
- */
- protected static char[] encodeHex(byte[] data, char[] toDigits) {
- int l = data.length;
- char[] out = new char[l << 1];
- // two characters form the hex value.
- for (int i = 0, j = 0; i < l; i++) {
- out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
- out[j++] = toDigits[0x0F & data[i]];
- }
- return out;
- }
-
- /**
- * 将字节数组转换为十六进制字符串
- *
- * @param data
- * byte[]
- * @return 十六进制String
- */
- public static String encodeHexStr(byte[] data) {
- return encodeHexStr(data, true);
- }
-
- /**
- * 将字节数组转换为十六进制字符串
- *
- * @param data
- * byte[]
- * @param toLowerCase
- * <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
- * @return 十六进制String
- */
- public static String encodeHexStr(byte[] data, boolean toLowerCase) {
- return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
- }
-
- /**
- * 将字节数组转换为十六进制字符串
- *
- * @param data
- * byte[]
- * @param toDigits
- * 用于控制输出的char[]
- * @return 十六进制String
- */
- protected static String encodeHexStr(byte[] data, char[] toDigits) {
- return new String(encodeHex(data, toDigits));
- }
-
- /**
- * 将十六进制字符数组转换为字节数组
- *
- * @param data
- * 十六进制char[]
- * @return byte[]
- * @throws RuntimeException
- * 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
- */
- public static byte[] decodeHex(char[] data) {
-
- int len = data.length;
-
- if ((len & 0x01) != 0) {
- throw new RuntimeException("Odd number of characters.");
- }
-
- byte[] out = new byte[len >> 1];
-
- // two characters form the hex value.
- for (int i = 0, j = 0; j < len; i++) {
- int f = toDigit(data[j], j) << 4;
- j++;
- f = f | toDigit(data[j], j);
- j++;
- out[i] = (byte) (f & 0xFF);
- }
-
- return out;
- }
-
- /**
- * 将十六进制字符转换成一个整数
- *
- * @param ch
- * 十六进制char
- * @param index
- * 十六进制字符在字符数组中的位置
- * @return 一个整数
- * @throws RuntimeException
- * 当ch不是一个合法的十六进制字符时,抛出运行时异常
- */
- protected static int toDigit(char ch, int index) {
- int digit = Character.digit(ch, 16);
- if (digit == -1) {
- throw new RuntimeException("Illegal hexadecimal character " + ch
- + " at index " + index);
- }
- return digit;
- }
-
- }
感悟:当时只是想着解决问题,没有想清楚里面的逻辑,今天恰好有点空闲,看了下原因,对java里面的二进制、utf8编码等基础的东西有了更深的理解,所以编码遇到问题,极有可能就是自己的知识盲点,解决这个盲点,就能更进一步。
作者:java小王子
链接:http://www.javaheidong.com/blog/article/997/f93526a0bc2267a8e4d5/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!