中文数据网络传输转码与解码过程浅析

来源:互联网 发布:113什么意思 网络聊天 编辑:程序博客网 时间:2024/05/17 08:07

       网络中传输数据,尤其是中文必然会遇到,转码与解码过程,中文产生乱码问题也就发生在该过程的某一环节,下面我将用代码的方式模拟整个转码和解码过程,相信理解此文之后,对所有中文乱码都会找到原因并处理之。在此之前,我们首先解一下网络发送数据的过程。以中文为例:中文的传输过程具体可能是:内存中unicode -> 编码阶段gbk, gb18030,gb2312,utf8 -> 到ISO8859-1 ->最后到可能的base64编码。其实传输ISO8859-1的字符就已经可以进行转换了,后面要进行Base64编码,我个人理解是为了网络发送和接受数据串简单,仅仅用基本的64个字符表示而已(个人观点,如有纰漏请不吝赐教!)。本例为了方便理解中文转码过程,没有进行base64的再次编码,关于base64编码与解码比较简单,请不理解的求助于网络。

       下面我们开始上代码:

       代码: Byte2HexUtil.java

package zmx.util;import java.math.BigInteger;/** *  * @author zhangwenchao * */public class Byte2HexUtil {      public static String bytes2hex01(byte[] bytes)      {          /**          * 第一个参数的解释,记得一定要设置为1          *  signum of the number (-1 for negative, 0 for zero, 1 for positive).          */          BigInteger bigInteger = new BigInteger(1, bytes);          return bigInteger.toString(16);      }             /**     * 方式二     *      * @param bytes     * @return     */    public static String bytes2hex02(byte[] bytes)    {        StringBuilder sb = new StringBuilder();        String tmp = null;        for (byte b : bytes)        {            // 将每个字节与0xFF进行与运算,然后转化为10进制,然后借助于Integer再转化为16进制            tmp = Integer.toHexString(0xFF & b);            if (tmp.length() == 1)// 每个字节8位,转为16进制标志,2个16进制位            {                tmp = "0" + tmp;            }            sb.append(tmp);        }         return sb.toString();     }        /**     * 方式三     *      * @param bytes     * @return     */    public static String bytes2hex03(byte[] bytes)    {        final String HEX = "0123456789abcdef";        StringBuilder sb = new StringBuilder(bytes.length * 2);        for (byte b : bytes)        {            // 取出这个字节的高4位,然后与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数            sb.append(HEX.charAt((b >> 4) & 0x0f));            // 取出这个字节的低位,与0x0f与运算,得到一个0-15之间的数据,通过HEX.charAt(0-15)即为16进制数            sb.append(HEX.charAt(b & 0x0f));        }         return sb.toString();    }        public static void main(String[] args) {byte[] bytes = {10,23,24,54};System.out.println(Byte2HexUtil.bytes2hex01(bytes));    System.out.println(Byte2HexUtil.bytes2hex02(bytes));    System.out.println(Byte2HexUtil.bytes2hex03(bytes));}    }


         这是一个工具类主要用于将byte[]数组转换为16进制字符串,16进制也可以理解为2进制的表现形式。

2、转码与解码过程:

package zmx.test;import zmx.util.Byte2HexUtil;public class T10 {public static void print(byte[] bytes) throws Exception{for(byte b: bytes){System.out.print(b+" "+ new String(new byte[]{b},"ISO8859-1")+"     ");}System.out.println();}public static void print(String str) throws Exception{for(int i=0;i<str.length();i++){System.out.print(str.charAt(i)+" "+ ((byte)str.charAt(i))+"     ");}System.out.println();}   public static void main(String[] args) throws Exception {   String chinese = "abc中文";  //中文字符串/*byte[] unicodes =  chinese.getBytes("UNICODE");System.out.println(unicodes.length);print(unicodes);System.out.println(Byte2HexUtil.bytes2hex03(unicodes));*/byte[] bg2312 = chinese.getBytes("GB2312"); //根据某一中文编码(ASCall和ISO8859-1不包含中文)获取字节数组System.out.println(bg2312.length); //不同的中文格式编码获取的字节数组长度不同。print(bg2312);String sender = new String(bg2312,"ISO8859-1");System.out.println("发送的数据:"+sender); //将该字节数组根据ISO8859-1转换为网络可传输的形式System.out.println(Byte2HexUtil.bytes2hex03(bg2312)); //本质上就是传输编码之后的字节数组String receive = sender;  //接受的数据System.out.println("接收的数据:"+receive);print(receive);byte[] receiveBytes = sender.getBytes("ISO8859-1");System.out.println(Byte2HexUtil.bytes2hex03(receiveBytes));System.out.println(new String(receiveBytes,"GB2312"));System.out.println(new String(receiveBytes,"GB2312").length());   }}


测试结果:

797 a     98 b     99 c     -42 Ö     -48 Ð     -50 Î     -60 Ä     发送的数据:abcÖÐÎÄ616263d6d0cec4接收的数据:abcÖÐÎÄa 97     b 98     c 99     Ö -42     Ð -48     Î -50     Ä -60     616263d6d0cec4abc中文5


 

        通过代码我们可以很明显的看出,对于字符串:“abc中文”,在发送前我们可以将其转换为“unicode/gb2312/utf-8”等不同格式的字节码数组,例如:byte[] bg2312 = chinese.getBytes("GB2312");使用GB2312进行转码。将得到的字节数组准换成16进制字符串之后得到“616263d6d0cec4”,其中,英文占1个字节 中文占两个字节。根据gb2312的编码规范:61-a,62-b,63-c,d6d0-中,cece-文。使用其他编码格式转码也是同理。之后我们把该字节数组转换为网络中可以传输的ISO8859-1的字符串,使用String sender = new String(bg2312,"ISO8859-1");得到:abcÖÐÎÄ。其实给数据串就可以发送了。但是为了不产生特殊字符等,真正传输过程又做了base64变换。得到字符串之后在进行逆变换就可以恢复中文。

       现在是不是对编码解码有了更深的理解,其实本质上就是这个简单,乱码也就是在变换过程中产生的,望读者对乱码产生原因多加分析。

 

 

 

 

 

 

 

0 0