java中文乱码

前言:日常开发过程中也经常遇到乱码的问题,此处做一个梳理总结,乱码问题产生的根源在于中文与英文不同的编码格式,因此除非有朝一日我们改用汉语编程,否则乱码问题不可避免。本文首先列举并分析常见的几种编码格式,然后,解释java中编码转化的原理,最后是自己遇到过的乱码问题

1. 编码

      计算机中存储信息以8bits为一个单元,叫做一个字节,所能表示的字符为0-255个显然是不够的,解决矛盾就需要使用char,而从char转化为字节的过程就是编码,反之就是解码,所以可以说,编码是为了存储,解码是为了阅读使用

2. 常见编码

1)ASCII 码 这个是大家最为熟悉的,也是我们接触和学习的第一种编码方式,一个字节的低七位来表示,共128个字符。

2)ISO-8859-1~ ISO-8859-15 是在ASCII码基础上制定的一系列编码规范,其中ISO-8859-1最常用。仍是单字节编码,总共能表示256个字符。

3)Unicode:最统一的编码,可以表示所有语言的字符,定长双字节,但不兼容ISO-8859-1,英文也用两个字节表示,不便于传输和存储

4)UTF-8/UTF-16 ISO提出的通用的Universal Code。16表示用两个字节表示一个字符,字符串操作时很方便,但是存储空间扩大了一倍,同样的信息,产生更大的网络传输流量。UTF-8变长编码,且完全兼容ASCII。是目前比较通用的一种编码格式。

5)GB2312/GBK 都是中文编码,不同之处在于GBK是在前者基础上进行了扩展,能表示更多的汉字,并兼容前者。

6)其他编码格式

3. java编码分析

内存:

      java用String表示字符串,String类提供了转换到字节的方法和将字节转换为String的构造函数。

public static void main(String[] args) {
        String str = "中文"; 
        try { 
            byte[] gbk = str.getBytes("GBK");
            System.out.println(gbk.length);
            System.out.println(new String(gbk));
            System.out.println(new String(gbk,"GBK"));
            System.out.println(new String(gbk,"UTF-8"));

        } catch (UnsupportedEncodingException e) { 
            e.printStackTrace(); 
        } 
    }

      上述代码,首先按照GBK编码格式进行编码,得到其实际存储的字节码,然后用String的构造函数,在拼接成字符串,可以指定编码格式,也可以不指定,在不指定的情况下则会使用环境默认的编码格式,本机IDE是GBK格式编码,因此第二行和第三行输出一致,均能正确解码,而强行使用UTF-8则会乱码。运行结果如下:

4
中文
中文
????

 
      String. getBytes(charsetName) 编码过程如下图所示:
    
I/O
      I/O操作以读取为例,涉及接口如下图:
    

      Reader 类是 Java 的 I/O 中读字符的父类,InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,负责在 I/O 过程中处理读取字节到字符的转换,而具体字节到字符的解码实现由 StreamDecoder 去实现。

4. 常见编码问题处理

内存:   

      在服务器上执行curl命令中包含中文,后端解析这个命令的代码中使用request.getParameter(“中文”)出现乱码,进行一次 String catName = new String(str.getBytes("ISO-8859-1"),"gbk");简单转换之后则可以正常获取到中文字符串。
      其实,JAVA在网络传输中一般使用是"ISO-8859-1",输出时需要进行转化,如:String str=new String(str.getBytes("环境编码格式"),"ISO-8859-1"); 经过网络编码后的中文,要正确显示在页面上一般需要使用类似Stirng str=new String(str.getBytes("ISO-8859-1"),"环境编码格式");这样的方式来解码。

I/O    

      使用InputStream.read()方法在数据流中读取字节,然后保存在一个byte[]数组中,最后转换为String。在我们读取文件时,读取字节的编码取决于文件所使用的编码格式,因此在转换为String过程中如果两者使用的编码格式不同也会出现编码问题。例如:stream.txt编码格式为UTF-8,那么通过字节流读取文件时所获得的数据流编码格式就是UTF-8,而我们在转化成String过程中如果不指定编码格式,则默认使用系统编码格式(此处应该是GBK)来解码操作,由于两者编码格式不一致,那么在构造String过程肯定会产生乱码,如下:

private static void IOSample() throws IOException{
        File file = new File("c:/stream.txt");
        InputStream input = new FileInputStream(file);
        StringBuffer buffer = new StringBuffer();
        byte[] bytes = new byte[128];
        for(int i ; (i = input.read(bytes))!=-1;){
//            buffer.append(new String(bytes,0,i));
            buffer.append(new String(bytes,0,i,"UTF-8"));
        }
        System.out.println(buffer);
    }

      当我们使用注释掉的buffer.append(new String(bytes,0,i));这种方式去转化的时候就会乱码。

杩欐槸瑕佷繚瀛樼殑涓枃瀛楃

  改为指定具体编码方式之后就得到了正确的输出:
这是要读取的中文字符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值