编码,解码,乱码,转码的理解。

对计算机而言,任何数字都是二进制的,字符也是用十六进制(其实也是二进制)来表示:比如”中文”,正常情况下(即没有错误的时候)存储为”4e2d 6587”,如果charset为”gbk”,则被编码为”d6d0 cec4”,然后返回字节”d6 d0 ce c4”.如果charset为”utf8”则最后是”e4 b8 ad e6 96 87”.如果是”iso8859-1”,则由于无法编码,最后返回 “3f 3f”(两个问号)。所以这里可以明确一个道理:不是我们看到的所有字符,都可以被解码,比如“ABCDEFG”,可以被解码为“utf-8”,也可以是“GBK”,甚至是“ASCII”,但是不能是”hex”,因为”HEX”不支持“G”这种编码格式。

也就是说,在不同编码格式下,字符的底层是不一样的,但是,我们明白一个道理就好:把字符正常显示就是一个查表的过程,当我们从网络,web,DB中接受数据的时候,我们得到肯定是一串01二进制(最底层),然后我们要做到找个“表”,去翻译这些二进制串,这个表就是字符编码。如server给我的是gbk的01序列,我们却用utf-8的01序列来做翻译,当然会乱码。所以乱码的根本原因在于我们没有找到一个张合适“翻译表”去翻译对方给我们的语言。

下面说说关于java中的字符串string的关于编码的方法吧:
1.String.getByte(“”); 这个函数是解码函数,就是说,原来的字符可以被哪种编码方式支持,我们就可以按照个编码过程来解码,这个函数返回的就是一串字节数组,也就是一个二进制的序列。
比如:

   String str = "中国";
        try {
            byte[] bytes = str.getBytes("gbk");
            byte[] bytes2=str.getBytes("utf-8");
            byte[] byte3=str.getBytes("ascii");//不支持
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

2.new String(byte[],”charset”) 这是java字符串处理的另一个标准函数,和上一个函数的作用相反,将字节数组按照charset编码进行组合识别,最后转换为unicode存储。参考上述getBytes的例子,”gbk” 和”utf8”都可以得出正确的结果”4e2d 6587”,但iso8859-1最后变成了”003f 003f”(两个问号)。
这个函数的使用示例如下:

             try {  
                   String s="中国";
                   byte []b=s.getBytes("utf-8");  
                    String str=new String(b,"utf-8");
                    String str1=new String(b,"gbk");  
                    System.out.println(str);
                    System.out.println(str1);  
                } catch (UnsupportedEncodingException e) {  
                    e.printStackTrace();  
                }  

运行上面的程序,你会发现,str 打印出来是正确,str1打印出来,是乱码的。

也就是说,原来是什么编码方式的,再从原来解码的方式来编码,才是正确的!其实,想想,乱码的原理,大概也就是这样的逻辑,
比如说java的IO流中有一个InputStreamReader(InputStream in,Charset cs) ,就是一个转码的桥梁,其实他做了什么呢?就是上面那段代码里面干的事情!比如网络中发送的字符是utf-8的,那么那个参数就写入“utf-8”,同理,如果是服务器是“gbk”,那就写“gbk,我们常常这样使用。(其实这个类就是主要负责转码操作的,因为转码)。


              BufferedReader m_bufferedreader=new BufferedReader(new InputStreamReader(m_inputstream,encode));  
StringBuffer m_stringbuffer=new StringBuffer();  
 while((one_line_string=m_bufferedreader.readLine())!=null){  
                  m_stringbuffer.append(one_line_string);//缓存String  

样使用字符流还缓存流来读入网络中的字符,还用stirngBufferer来做缓存,效率很高。
然后我说下这次项目里面碰到的一个问题:
我写一个网盘的客户端,要得到服务器发过来的HTTP报文中的报文头的文件,所以我要从报文中得到文件的名称,英文好还,中文就呵呵了,又乱码了,我和后台的人沟通,结果发现对的啊,也是无语了,后来查找了好久才看到,原来HTTP报文的问题:
HTTP报文的编码格式只能是ISO-8895-1,不能是别的,所以,HTTP服务器在发送报文的时候,把原来的编码的格式先转换成为了ISO-8895-1
就是这样的形式:

      String s="计算机";  
  try {  
    byte []b=s.getBytes("utf-8");  
    String str=new String(b,"iso-8895-1");  
    System.out.println(str);  
   catch (UnsupportedEncodingException e) {  
e.printStackTrace();  

所以,在不管你说server的编码格式utf-8,我这边也是用utf-8来解析的啊,都没用的,你拿到的就是一串乱码的东西,这样解决才是正确的:

byte []b=filename.getBytes("ISO-8859-1");  
filename=new String(b,"utf-8");  

也许这个例子不好理解,我做个比喻,服务器,先是把一个字符串(假设原来的是utf-8的编码格式的),然后服务器将这个字符串按照utf-8的标准,解码为二进制的字符串,再进行ISO-8859-1的编码,发送给客户端(但是,不管变成什么样子的二进制,原来的字符串想正确显示,就只有通过utf-8),所以,现在客户端就必须先将拿到的字符串先按照ISO-8859-1解码为原来的utf-8的二进制,再重新组合成为utf-8.方能正确显示

这就是这个问题的所在,我看到网上很少有解答的,还是给大家说下吧。主要是HTTP的报文头部的限制编码的问题。
编码一直都是一个比较基础的问题,无论在网络,加密解密,还是数据库操作,都请注重。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值