博客信息

IO流之字节编码(概述、Jsp的乱码原理、GBK与UTF-8编码表错乱之联通戏法)

发布时间:『 2019-06-16 09:42』  博客类别:java基础  阅读(799)

概述

字符流的出现为了方便操作字符;

更重要的是加入了编码转换;

通过子类转换流来完成;

InputStreamReadme

OutputStreamWriter

 

在两个对象进行构造的时候可以加入字符集;

 

编码表的由来

计算机只能识别二进制数据,早期由来是电信号;

为了方便应用计算机,让它可以识别各个国家的文字;

就将各个国家的文字用数字来表示,并一一对应,形成一张表;

这就是编码表;

 

常见的编码表:

ASCII:美国标准信息交换码,用一个字节的7位就可以表示;

ISO8859-1:拉丁码表,欧洲码表,用一个字节的8位表示;

GB2312:中国的中文编码表;

GBK:中国的中文编码表升级,融合了更多的中文文字字符号;

Unicode:攻击标准码,融合了多种文字;

所有文字都用两个字节来表示,Java语言使用的就是unicode

UTF-8:最多用三个字节来表示一个字符;

......

 

 

“你好”的文字以两种编码表的方式存放到指定的文件中


package com.javaxl.io.charset;

import java.io.*;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-06-16 19:50
 */
public class EncodeStreamDemo {
    public static void main(String[] args) throws IOException {
        write();
        read();
    }

    public static void write() throws IOException {
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("C:\\encodeStreamDemo.txt"),"UTF-8");
        osw.write("你好");
        osw.close();
    }

    public static void read() throws IOException {
        InputStreamReader isr = new InputStreamReader(new FileInputStream("C:\\encodeStreamDemo.txt"),"UTF-8");
        char[] cbuf = new char[16];
        int len = isr.read(cbuf);
        System.out.println(new String(cbuf,0,len));
        isr.close();
    }
}


注意:

写入流和读取流字符编码一致的话,那么不会出现乱码问题;

如果写入流编码是UTF-8,读取流解码参照的码表是GBK,那么会得到看不懂的三个字符;

如果写入流编码是GBK,读取流解码参照的码表UTF-8,那么会得到看不懂的两个字符;

原因参考下面截图

 

图解文件读取字符乱码

小李飞刀_IO流


Jsp的乱码原理

 

编码:字符串变成字节数组;

解码:字节数组变成字符串;

 

String-->byte[]str.getBytes(charsetName);

Byte[]-->Stringnew String(byte[],charsetName);


package com.javaxl.io.charset;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-06-16 20:06
 *
 * jsp乱码问题
 */
public class JspEncodeDemo {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "你好";
        byte[] b1 = s.getBytes("GBK");

        System.out.println(Arrays.toString(b1));
        String s1 = new String(b1, "ISO8859-1");
        System.out.println("s1=" + s1);

        byte[] b2 = s1.getBytes("ISO8859-1");
        System.out.println(Arrays.toString(b2));

        String s2 = new String(b2, "GBK");
        System.out.println("s2=" + s2);
    }
}


小李飞刀_IO流


小李飞刀_IO流



UTF-8GBK相互编码的问题


package com.javaxl.io.charset;

import java.io.UnsupportedEncodingException;
import java.util.Arrays;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-06-16 20:06
 *
 * UTF-8与GBK相互编码的问题
 */
public class EncodeExceptionDemo {

    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "你好";
        byte[] b1 = s.getBytes("GBK");

        System.out.println(Arrays.toString(b1));
        String s1 = new String(b1, "UTF-8");
        System.out.println("s1=" + s1);

        byte[] b2 = s1.getBytes("UTF-8");
        System.out.println(Arrays.toString(b2));

        String s2 = new String(b2, "GBK");
        System.out.println("s2=" + s2);
    }
}


小李飞刀_IO流


注意:GBKUTF-8相互编码解码会有问题,因为都识别中文,一个对应两个字节,一个对应三个字节;所以编码解码编码解码最终不能得到最初的字符串;


GBKUTF-8编码表错乱之联通

现象描述:

在普通记事本中输入“你好”二字,保存后打开,显示“你好”二字,这不会出现任何问题;

但是删掉“你好”二字,写入“联通”二字,保存后打开,会发现“联通”二字,不会出现,普通记事本中出现了乱码;

 

原因:


package com.javaxl.io.charset;

import java.io.UnsupportedEncodingException;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-06-16 20:15
 */
public class LianTongDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "联通";
        byte[] bytes = s.getBytes("GBK");
        for (byte b : bytes) {
            System.out.println(Integer.toBinaryString(b & 255));
        }
    }
}


小李飞刀_IO流


小李飞刀_IO流


小李飞刀_IO流




“联通”二字用GBK进行编码后,所得到的二进制,正好对应着UTF-8中的两个字节的解码方式(UTF-8最多用三个字节表示一个汉字,这里正好符合两个字节表示一个汉字的规律),

但是GBK所编码出来的二进制(两个字节),又在UTF-8中找不到对应的汉字,所以出现了乱码;




关键字:     Java基础       IO流       字节编码       乱码  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有