美文网首页Java 杂谈IT技术篇
java基础io流之乱码的解决办法

java基础io流之乱码的解决办法

作者: 6c38bc5d384c | 来源:发表于2019-01-17 14:28 被阅读2次

    说到乱码,相信很多初学程序的小白们都遇见过,并且也并不知道如何去解决这个问题,今天就给大家分享一下有关乱码的解决方法,在这之前,我觉得有必要先来聊一下编码的知识。

    java技术学习qun:59,789,1510,每天分享一点java知识干货!

    String(byte[] bytes, String charsetName):通过指定的字符集解码字节数组

    byte[] getBytes(String charsetName):使用指定的字符集合把字符串编码为字节数组

    编码:把看得懂的变成看不懂的

    String -- byte[]

    解码:把看不懂的变成看得懂的

    byte[] -- String

    因此字节流读取的数据是编码过的数据,我们解码就行了。

    编码问题简单,只要编码解码的格式是一致的。

    计算机只能识别二进制数据,早期由来是电信号。为了方便应用计算机,让它可以识别各个国家的文字。就将各个国家的文字用数字来表示,并一一对应,形成一张表。

    ASCII:美国标准信息交换码。

    用一个字节的7位可以表示。

    ISO8859-1:拉丁码表。欧洲码表

    用一个字节的8位表示。

    GB2312:中国的中文编码表。

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

    GB18030:GBK的取代版本

    BIG-5码 :通行于台湾、香港地区的一个繁体字编码方案,俗称“大五码”。

    Unicode:国际标准码,融合了多种文字。

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

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

    UTF-8不同,它定义了一种“区间规则”,这种规则可以和ASCII编码保持最大程度的兼容:

    它将Unicode编码为00000000-0000007F的字符,用单个字节来表示�

    它将Unicode编码为00000080-000007FF的字符用两个字节表示

    它将Unicode编码为00000800-0000FFFF的字符用3字节表示

    示例:

    String s = "你好";

    byte[] bytes1 = s.getBytes();

    System.out.println(Arrays.toString(bytes1));//[-28, -67, -96, -27, -91, -67] 默认编码utf-8

    byte[] bytes2 = s.getBytes("GBK");

    System.out.println(Arrays.toString(bytes2));//[-60, -29, -70, -61]

    byte[] bytes3 = s.getBytes("UTF-8");

    System.out.println(Arrays.toString(bytes3));//[-28, -67, -96, -27, -91, -67]

    String s1 = new String(bytes1);

    System.out.println(s1);//你好

    String s2 = new String(bytes2,"GBK");

    System.out.println(s2);//你好

    String s3 = new String(bytes2,"gbk");

    System.out.println(s3);//你好

    String s4 = new String(bytes3);

    System.out.println(s4);//你好

    String s5 = new String(bytes3,"gbk");

    System.out.println(s5);//浣犲ソ

    虽然字节流有解决乱码的方案,但并不方便,所以java io流就设计出了转换流,一场乱码引发的变革。

    (OutputStreamWriter、InputStreamReader)

    OutputStreamWriter(OutputStream out):根据默认编码把字节流的数据转换为字符流

    OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流

    java技术学习qun:59,789,1510,每天分享一点java知识干货!

    乱码导火索:

    在io流里,先诞生了字节流,但是字节流读取数据会有乱码的问题(读中文会乱码)。比如:

    FileInputStream fis = new FileInputStream("a.txt");

    // int by = 0;

    // while ((by=fis.read() )!= -1) {

    // System.out.print((char)by);//bcdbcdbcdbcdbcdbcdhello 中�

    // //因为还正常,中文就乱码了,有什么办法解决吗,有,就是有点麻烦

    // }

    从文件中读取中文会有乱码,当然字节流有解决措施。

    FileInputStream fis = new FileInputStream("a.txt");

    byte[] bytes = new byte[1024];

    int len = 0;

    while ((len = fis.read(bytes)) != -1) {

    System.out.println(new String(bytes,0,len));//bcdbcdbcdbcdbcdbcdhello 中国

    //查看new String()的源码,this.value = StringCoding.decode(bytes, offset, length);

    //点进decode,循序渐进发现,默认编码是UTF-8

    //通过源码,也看到了这个方法public String(byte bytes[], int offset, int length, String charsetName)

    }

    但是解码这并不是字节流做的,而是String的功能。查看String的源码,构造方法有解码功能,并且默认编码是utf-8。

    把字节流转换为字符流。

    //创造对象

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));//查看源码,java8 默认utf-8

    //写数据

    osw.write("中国");

    //释放资源

    osw.close();//close包含了close和flush的作用

    一般默认编码就够了。

    java技术学习qun:59,789,1510,每天分享一点java知识干货!

    查看源码,发现OutputStreamWriter有5个write方法。

    /*

    * OutputStreamWriter的方法:

    * public void write(int c):写一个字符

    * public void write(char[] cbuf):写一个字符数组

    * public void write(char[] cbuf,int off,int len):写一个字符数组的一部分

    * public void write(String str):写一个字符串

    * public void write(String str,int off,int len):写一个字符串的一部分

    *

    * 面试题:close()和flush()的区别?

    * A:close()关闭流对象,但是先刷新一次缓冲区。关闭之后,流对象不可以继续再使用了。

    * B:flush()仅仅刷新缓冲区,刷新之后,流对象还可以继续使用。

    */

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c.txt"));//查看源码,java8 默认utf-8

    //写一个字符

    osw.write('a');

    osw.write(97);

    osw.write('中');

    // 为什么数据没有进去呢?

    // 原因是:字符 = 2字节

    // 文件中数据存储的基本单位是字节。

    // void flush()

    osw.flush();

    //写一个字符数组

    char[] chars = {'a','b','中','国'};

    osw.write(chars);

    osw.flush();

    //写一个字符数组的一部分

    osw.write(chars,2,2);

    osw.flush();

    //写一个字符串

    osw.write("中国");

    //写一个字符串的一部分

    osw.write("中国你好",2,2);

    osw.close();

    InputStreamReader(InputStream is):用默认的编码读取数据,默认utf-8

    InputStreamReader(InputStream is,String charsetName):

    java技术学习qun:59,789,1510,每天分享一点java知识干货!

    用指定的编码读取数据

    //创建对象

    InputStreamReader isr = new InputStreamReader(new FileInputStream("b.txt"));//默认编码utf-8

    InputStreamReader isr1 = new InputStreamReader(new FileInputStream("b.txt"),"gbk");//可指定编码

    //读数据

    int ch = 0;

    while ((ch = isr.read()) != -1) {

    System.out.print((char)ch);//中国

    }

    //释放资源

    isr.close();

    //只有文档的编码和读取的编码一致才不会乱码。

    查看源码知道InputStreamReader有2个read方法。

    /*

    * InputStreamReader的方法:

    * int read():一次读取一个字符

    * int read(char[] chs):一次读取一个字符数组

    */

    InputStreamReader isr = new InputStreamReader(new FileInputStream("c.txt"));

    //读一个字符

    // int ch = 0;

    // while ((ch = isr.read()) != -1) {

    // System.out.print((char) ch);//9797200139798200132226920013222691020013222692032022909/

    // //aa中ab中国中国

    // //中国你好

    // }

    //isr.close();

    //读一个字符数组

    char[] chars =new char[1024];

    int len = 0;

    while ((len = isr.read(chars)) != -1) {

    System.out.println(chars.length);//1024

    System.out.println(new String(chars,0,len));

    //aa中ab中国中国

    //中国你好

    }

    isr.close();

    现在我们可以通过转换流升级字节流复制文件的方式了。

    InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));

    OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("e:\a.txt"));

    char [] chars = new char[1024];

    int len = 0 ;

    while ((len = isr.read(chars)) != -1) {

    osw.write(chars,0,len);

    osw.flush();

    }

    osw.close();

    isr.close();

    好了,本篇文章就分享到这里了。有兴趣的新手伙伴们可以关注收藏起来,以后需要的时候可以多看看。如果有正在学java的程序员,可来我们的java技术学习扣qun哦:59789,1510里面免费送java的视频系统教程!

    相关文章

      网友评论

        本文标题:java基础io流之乱码的解决办法

        本文链接:https://www.haomeiwen.com/subject/dbridqtx.html