美文网首页
Java 基础 43 转换流

Java 基础 43 转换流

作者: 小熊先生很不开心 | 来源:发表于2018-02-04 11:45 被阅读10次

1.1 转换流出现的原因

1.1.1 字节流读数据可能出现问题

  字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。

  文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。

  • 汉字存储的规则:
    • 左边的字节数据肯定是负数,
    • 右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。

1.1.2 案例代码

public class FileInputStreamDemo {
    public static void main(String[] args) throws IOException {
        //基本字节流一次读取一个字节
//      FileInputStream fis = new FileInputStream("a.txt");
//      
//      int by;
//      while((by=fis.read())!=-1) {
//          System.out.print((char)by);
//      }
//      
//      fis.close();
        
        //String s = "hello";
        //[104, 101, 108, 108, 111]
        String s = "你好";
        //[-60, -29, -70, -61]
        byte[] bys = s.getBytes();
        System.out.println(Arrays.toString(bys));
    }
}

1.1.3 转换流的组成部分

转换流 = 字节流 + 编码表

这句话怎么理解 ? 往下看, 先说编码表

1.2 编码表概述和常见编码表

1.2.1 什么是编码表?

  • 编码表:
    • 由字符及其对应的数据组成的一张表
    • ASCII:
      • ‘a’ 97
      • ‘A’ 65
      • ‘0’ 48
  • 常见的编码表:
    • ASCII : 美国标准信息交换码, 用一个字节的7位表示数据
    • ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII
    • GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII
    • UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, - 兼容ASCII
      • 用在网页上可以统一页面中的中文简体繁体和其他语言的显示.

1.2.2 乱码问题

针对同一个数据, 采用的编码和解码不一致导致

Garbled.png

1.3 String类中的编码和解码问题

1.3.1 方法摘要&编码和解码

  • 编码

    • 把看得懂的变成看不懂的
      • public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
    • 使用指定的字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
  • 解码

    • 把看不懂的变成看得懂的
      • public String(byte[] bytes, String charsetName)
    • 通过使用指定的 charset解码指定的 byte 数组,构造一个新的 String。

    重点强调 : 编码和解码的方式需要一致

1.3.2 案例代码

public class StringDemo {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //定义一个字符串
        String s = "你好";
        
        //编码
        //byte[] bys = s.getBytes();//使用平台的默认字符集将此 String 编码为 byte 序列
        //默认编码是GBK
        //[-60, -29, -70, -61]
        //byte[] bys = s.getBytes("GBK"); //指定编码GBK
        //[-60, -29, -70, -61]
        byte[] bys = s.getBytes("UTF-8"); //指定编码UTF-8
        //[-28, -67, -96, -27, -91, -67]
        System.out.println(Arrays.toString(bys));
        
        //解码
        //String ss = new String(bys); //通过使用平台的默认字符集解码指定的 byte 数组
//      String ss = new String(bys,"GBK");//指定编码GBK
        String ss = new String(bys,"UTF-8");//指定编码UTF-8
        System.out.println(ss);
    }
}

1.4 转换流中的编码和解码问题

1.4.1 转换流指的是?

  转换流其实就是一个字符流。

  转换流 = 字节流 + 编码表

1.4.2 转换流的构造方法

  • OutputStreamWriter 字符输出流

    • public OutputStreamWriter(OutputStream out)
      • 根据默认编码把字节流的数据转换为字符流
    • public OutputStreamWriter(OutputStream out,String charsetName)
      • 根据指定编码把字节流数据转换为字符流
  • InputStreamReader 字符输入流

    • public InputStreamReader(InputStream in)
      • 用默认的编码读数据
    • public InputStreamReader(InputStream in,String charsetName)

1.4.3 案例代码

public class ConversionStreamDemo {
    public static void main(String[] args) throws IOException {
        //public OutputStreamWriter(OutputStream out):默认编码GBK
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"));
        //public OutputStreamWriter(OutputStream out,String charsetName)
        //OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"GBK");
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"UTF-8");
        //调用写数据的方法
        osw.write("你好");
        //释放资源
        osw.close();
        System.out.println("------------------------");
        
        //public InputStreamReader(InputStream in):默认编码GBK
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"));
        //public InputStreamReader(InputStream in,String charsetName)
        //InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"GBK");
        InputStreamReader isr = new InputStreamReader(new FileInputStream("osw.txt"),"UTF-8");
        //读数据:一次读取一个字符数据
        int ch;
        while((ch=isr.read())!=-1) {
            System.out.print((char)ch);
        }
        //释放资源
        isr.close();
        
    }
}

1.5 OutputStreamWriter写数据的5种方式

1.5.1 方法摘要

* 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):写一个字符串的一部分

1.5.2 案例代码


public class OutputStreamWriterDemo {
    public static void main(String[] args) throws IOException {
        //创建字符输出流对象
        OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("b.txt"));
        
        //public void write(int c):写一个字符
//      osw.write(97);
//      osw.write('a');
        //写完数据后,没有发现数据,为什么呢?
        //1字符=2字节
        //文件中的数据存储的基本单位是字节
        
        //public void write(char[] cbuf):写一个字符数组
//      char[] chs = {'a','b','c','d','e'};
//      osw.write(chs);
        
        //public void write(char[] cbuf,int off,int len):写一个字符数组的一部分
//      char[] chs = {'a','b','c','d','e'};
//      osw.write(chs, 1, 3);
        
        //public void write(String str):写一个字符串
//      osw.write("hello");
        
        //public void write(String str,int off,int len):写一个字符串的一部分
        osw.write("hello", 0, 3);
        
//      //void flush():刷新该流的缓冲
//      osw.flush();
//      
//      //释放资源
        osw.close(); //关闭此流,但要先刷新它
    }
}

1.6 InputStreamReader读数据的2种方式

1.6.1 方法摘要

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

1.6.2 案例代码

public class InputStreamReaderDemo {
    public static void main(String[] args) throws IOException {
        //创建字符输入流对象
//      InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"));
        InputStreamReader isr = new InputStreamReader(new FileInputStream("OutputStreamWriterDemo.java"));
        
        //public int read():一次读取一个字符
//      int ch;
//      while((ch=isr.read())!=-1) {
//          System.out.print((char)ch);
//      }
        
        //public int read(char[] cbuf):一次读取一个字符数组
        char[] chs = new char[1024];
        int len;
        while((len=isr.read(chs))!=-1) {
            System.out.print(new String(chs,0,len));
        }
        
        //释放资源
        isr.close();
    }
}

相关文章

  • Java 基础 43 转换流

    1.1 转换流出现的原因 1.1.1 字节流读数据可能出现问题   字节流一次读取一个字节的方式读取带有汉字的文件...

  • IO流(二)~ 字符流

    一、转换流出现的原因及思想 1. 转换流出现的原因及思想 由于字节流操作中文不是特别方便,所以,java就提供了转...

  • Java基础-IO流-转换流

    Java工程师知识树[https://www.jianshu.com/p/db77d19a25f6] / Ja...

  • 数据类型在jvm中的内存分配-01-29

    【转】 java面经(基础)

  • Java学习笔记 20 - 转换流、缓冲流

    本文主要内容1、转换流2、缓冲流3、各种流文件复制方式的效率比较4、IO流对象的操作规律 01转换流 A: 转换流...

  • Java IO之转换流的使用

    简介 转换流提供了在字节流和字符流之间的转换。 Java API提供了两个转换流:InputstreamReade...

  • 2019-03-26

    Java转换流: java中最常见的便是数据类型间的转换了,先来简单介绍一下什么是转换流:其实就是将一个类型转变成...

  • 技术转载——JVM的架构和执行过程

    JVM也叫Java Virtual Machine,它是java程序运行的基础,负责将java bytecode转...

  • No_16_0322 Java基础学习第二十二天

    [TOC] 转换流出现的原因及思想 由于字节流操作中文不是特别方便,所以,java就提供了转换流。 字符流 = 字...

  • Java基础

    注:采转归档,自己学习查询使用 Java基础01 从HelloWorld到面向对象Java基础02 方法与数据成员...

网友评论

      本文标题:Java 基础 43 转换流

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