本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2024-11(1)

json数组分成两份二进制发送,我接受之后通过new两个String报乱码问题原因解析

发布于2020-11-19 20:54     阅读(1236)     评论(0)     点赞(14)     收藏(0)


底层json由于很长,所以分成多次发送,我每次接受到一部分就new String(),最后再把多个String拼接成一个json数组,刚开始系统运行良好,后来莫名其妙就会出现乱码,最后发现是new String()出现的问题,这里做一个模拟;

1、json数组

  1. {
  2. "a": "我们来自不同的世界"
  3. }

2、解析通过toBytes之后的数组

  1. String a1 = "{\n" +
  2. " \"a\": \"我们来自不同的世界\"\n" +
  3. "}";
  4. System.out.println(Arrays.toString(a1.getBytes()));
  5. 输出之后的数组
  6. [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,
  7. -124, -28, -72, -106, -25, -107, -116, 34, 10, 125]

3、为了模拟我把这个数组分成两个部分,然后通过new String拼接

  1. public static void main(String[] args) {
  2. // String a1 = "{\n" +
  3. // " \"a\": \"我们来自不同的世界\"\n" +
  4. // "}";
  5. // System.out.println(Arrays.toString(a1.getBytes()));
  6. 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};
  7. byte[] b = {-124, -28, -72, -106, -25, -107, -116, 34, 10, 125};
  8. System.out.println(new String(a)+new String(b));
  9. }

输出的结果:

  1. {
  2. "a": "我们来自不同��世界"
  3. }

当然,如果运气好,刚好接收的字节没有汉字拆分,这种组合是没有问题的,如下

  1. public static void main(String[] args) {
  2. // String a1 = "{\n" +
  3. // " \"a\": \"我们来自不同的世界\"\n" +
  4. // "}";
  5. // System.out.println(Arrays.toString(a1.getBytes()));
  6. 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};
  7. byte[] b = { -28, -72, -106, -25, -107, -116, 34, 10, 125};
  8. System.out.println(new String(a)+new String(b));
  9. }

结果

  1. {
  2. "a": "我们来自不同的世界"
  3. }

原因解析

字符串被解析成字节数组的时候,我的intellij默认使用的是UTF-8编码,所以一个汉字会被编码成三个字节,此文中的‘的’汉字编码为: -25, -102,-124

而且我们通过new String发现,这三个字节就是汉字‘的’

  1. byte[] c = { -25, -102,-124};
  2. System.out.println(new String(c));
  3. 输出:的

如果按照我们第一种乱码的分数组方式,会发现第一个字节数组a中包含-25,-102,第二个数组b包含-124,在new String()的时候,默认还是使用UTF8编码,因为不认识-25,-102和-124,所以变成两个乱码��

解决方法

1、将数组a和数组b组合成一个数组之后,再使用new String()处理

2、因为我是一次只能接收一块,然后使用redis临时储藏这一块数据,所以我把收到的数据都转换成为了16进制字符串,最后再把16进制字符串从redis获取,全部合并,再转换成json字符串,也能解决问题

  1. HexUtils.encodeHexStr(blockData)
  2. new String(HexUtils.decodeHex(allData.toCharArray()))

工具类如下,很久以前在博客上看到的,不晓得是那一片博客了

  1. public class HexUtils {
  2. /**
  3. * 用于建立十六进制字符的输出的小写字符数组
  4. */
  5. private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
  6. '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
  7. /**
  8. * 用于建立十六进制字符的输出的大写字符数组
  9. */
  10. private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
  11. '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
  12. /**
  13. * 将字节数组转换为十六进制字符数组
  14. *
  15. * @param data
  16. * byte[]
  17. * @return 十六进制char[]
  18. */
  19. public static char[] encodeHex(byte[] data) {
  20. return encodeHex(data, true);
  21. }
  22. /**
  23. * 将字节数组转换为十六进制字符数组
  24. *
  25. * @param data
  26. * byte[]
  27. * @param toLowerCase
  28. * <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
  29. * @return 十六进制char[]
  30. */
  31. public static char[] encodeHex(byte[] data, boolean toLowerCase) {
  32. return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
  33. }
  34. /**
  35. * 将字节数组转换为十六进制字符数组
  36. *
  37. * @param data
  38. * byte[]
  39. * @param toDigits
  40. * 用于控制输出的char[]
  41. * @return 十六进制char[]
  42. */
  43. protected static char[] encodeHex(byte[] data, char[] toDigits) {
  44. int l = data.length;
  45. char[] out = new char[l << 1];
  46. // two characters form the hex value.
  47. for (int i = 0, j = 0; i < l; i++) {
  48. out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
  49. out[j++] = toDigits[0x0F & data[i]];
  50. }
  51. return out;
  52. }
  53. /**
  54. * 将字节数组转换为十六进制字符串
  55. *
  56. * @param data
  57. * byte[]
  58. * @return 十六进制String
  59. */
  60. public static String encodeHexStr(byte[] data) {
  61. return encodeHexStr(data, true);
  62. }
  63. /**
  64. * 将字节数组转换为十六进制字符串
  65. *
  66. * @param data
  67. * byte[]
  68. * @param toLowerCase
  69. * <code>true</code> 传换成小写格式 , <code>false</code> 传换成大写格式
  70. * @return 十六进制String
  71. */
  72. public static String encodeHexStr(byte[] data, boolean toLowerCase) {
  73. return encodeHexStr(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
  74. }
  75. /**
  76. * 将字节数组转换为十六进制字符串
  77. *
  78. * @param data
  79. * byte[]
  80. * @param toDigits
  81. * 用于控制输出的char[]
  82. * @return 十六进制String
  83. */
  84. protected static String encodeHexStr(byte[] data, char[] toDigits) {
  85. return new String(encodeHex(data, toDigits));
  86. }
  87. /**
  88. * 将十六进制字符数组转换为字节数组
  89. *
  90. * @param data
  91. * 十六进制char[]
  92. * @return byte[]
  93. * @throws RuntimeException
  94. * 如果源十六进制字符数组是一个奇怪的长度,将抛出运行时异常
  95. */
  96. public static byte[] decodeHex(char[] data) {
  97. int len = data.length;
  98. if ((len & 0x01) != 0) {
  99. throw new RuntimeException("Odd number of characters.");
  100. }
  101. byte[] out = new byte[len >> 1];
  102. // two characters form the hex value.
  103. for (int i = 0, j = 0; j < len; i++) {
  104. int f = toDigit(data[j], j) << 4;
  105. j++;
  106. f = f | toDigit(data[j], j);
  107. j++;
  108. out[i] = (byte) (f & 0xFF);
  109. }
  110. return out;
  111. }
  112. /**
  113. * 将十六进制字符转换成一个整数
  114. *
  115. * @param ch
  116. * 十六进制char
  117. * @param index
  118. * 十六进制字符在字符数组中的位置
  119. * @return 一个整数
  120. * @throws RuntimeException
  121. * 当ch不是一个合法的十六进制字符时,抛出运行时异常
  122. */
  123. protected static int toDigit(char ch, int index) {
  124. int digit = Character.digit(ch, 16);
  125. if (digit == -1) {
  126. throw new RuntimeException("Illegal hexadecimal character " + ch
  127. + " at index " + index);
  128. }
  129. return digit;
  130. }
  131. }

感悟:当时只是想着解决问题,没有想清楚里面的逻辑,今天恰好有点空闲,看了下原因,对java里面的二进制、utf8编码等基础的东西有了更深的理解,所以编码遇到问题,极有可能就是自己的知识盲点,解决这个盲点,就能更进一步。

 



所属网站分类: 技术文章 > 博客

作者:java小王子

链接:http://www.javaheidong.com/blog/article/997/f93526a0bc2267a8e4d5/

来源:java黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

14 0
收藏该文
已收藏

评论内容:(最多支持255个字符)