zoukankan      html  css  js  c++  java
  • IO流输入输出流,字符字节流

     一、流

    1.流的概念 
    流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象。即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
    2.流的分类
    根据处理数据类型的不同分为:字符流和字节流,字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。
    根据数据流向不同分为:输入流和输出流

    3.字符流和字节流
    3.1 字符流的由来: 因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。 Java 内用 Unicode 编码存储字符,字符流处理类负责将外部的其他编码的字符流和 java 内 Unicode 字符流之间的转换。
    3.2 字节流和字符流的区别:
    (1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符为单位,根据码表映射字符,一次可能读多个字节。
    (2)处理对象不同:字节流能处理所有类型的数据(如图片、avi等),而字符流只能处理字符类型的数据。
    (3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候下后是会用到缓冲区的,是通过缓冲区来操作文件,我们将在下面验证这一点。

    结论:优先选用字节流。首先因为硬盘上的所有文件都是以字节的形式进行传输或者保存的,包括图片等内容。但是字符只是在内存中才会形成的,所以在开发中,字节流使用广泛。从效率而言,字符流(一次可以处理一个缓冲区)一次操作比字节流(一次一个字节)效率高。

    4.输入流和输出流
    对输入流只能进行读操作,对输出流只能进行写操作,程序中需要根据待传输数据的不同特性而使用不同的流。输入输出流的流向是相对于程序而言。
    输入流:InputStream 读入 就是从外部文件中读取数据到程序。对应 Reader;
    输出流: OutputStream 写出 就是将数据从程序写入到外部文件。对应 Writer;

    二、字节流

    1.字节流概述
    1)字节流和字符流的基本操作是相同的,但是要想操作媒体流就需要用到字节流。
    2)字节流因为操作的是字节,所以可以用来操作媒体文件。(媒体文件也是以字节存储的)
    3)读写字节流:InputStream 输入流(读)和OutputStream 输出流(写)
    4)字节流操作可以不用刷新流操作。
    5)InputStream特有方法:
    int available(); //返回文件中的字节个数

    注:可以利用此方法来指定读取方式中传入数组的长度,从而省去循环判断。但是如果文件较大,而虚拟机启动分配的默认内存一般为64M。当文件过大时,此数组长度所占内存空间就会溢出。所以,此方法慎用,当文件不大时,可以使用

    2. 字节流缓冲区
    1)缓冲区的出现时为了提高流的操作效率而出现的.
    2)需要被提高效率的流作为参数传递给缓冲区的构造函数
    3)在缓冲区中封装了一个数组,存入数据后一次取出 

    3.输入字节流InputStream
    定义和结构说明:
    从输入字节流的继承图可以看出:InputStream 是所有的输入字节流的父类,它是一个抽象类。
    ByteArrayInputStream、StringBufferInputStream、FileInputStream 是三种基本的介质流,它们分别从Byte 数组、StringBuffer、和本地文件中读取数据。
    PipedInputStream 是从与其它线程共用的管道中读取数据,与Piped 相关的知识后续单独介绍。
    ObjectInputStream 和所有FilterInputStream的子类都是装饰流(装饰器模式的主角)。意思是FileInputStream类可以通过一个String路径名创建一个对象,FileInputStream(String name)。
    DataInputStream必须装饰一个类才能返回一个对象,DataInputStream(InputStream in)。 

    复制代码
    public static void main(String[] args) throws IOException { 
      File f=new File("aaa.txt"); //定位文件位置
      InputStream in=new FileInputStream(f); //创建字节输入流连接到文件
      byte[] b=new byte[1024]; //定义一个数组,用来存放读入的数据 byte数组的大小也可以根据文件大小来定 (int)f.length()
      int count =0; 
      int temp=0;
      while((temp=in.read())!=(-1)){ //in.read()是逐字节读的。当读到文件末尾时候返回-1
        b[count++]=(byte)temp; //将读到的字节存储到byte数组中 
      }
      in.close(); //关闭流
      System.out.println(new String(b)); //打印读取到的字节
    }
    复制代码

    注意:当读到文件末尾的时候会返回-1.正常情况下是不会返回-1的。


    加入字节缓冲输入流,提高了读取效率

    复制代码
    public static void main(String[] args) throws IOException { 
      File f=new File("aaa.txt"); //定位文件位置
      InputStream in=new FileInputStream(f); //创建字节输入流连接到文件
      BufferedInputStream bis=new BufferedInputStream(in); //创建缓冲字节流
      byte[] b=new byte[1024]; //定义一个数组,用来存放读入的数据 byte数组的大小也可以根据文件大小来定 (int)f.length()
      int count =0; 
      int temp=0;
      bis.read();
      while((temp=bis.read())!=(-1)){ //in.read()是逐字节读的。当读到文件末尾时候返回-1
        b[count++]=(byte)temp; //将读到的字节存储到byte数组中 
      }
      bis.close(); //关闭缓冲字节流
      in.close(); //关闭流
      System.out.println(new String(b)); //打印读取到的字节
    }
    复制代码

    4.输出字节流OutputStream

    定义和结构说明:

    IO 中输出字节流的继承图可见上图,可以看出:OutputStream 是所有的输出字节流的父类,它是一个抽象类。
    ByteArrayOutputStream、FileOutputStream是两种基本的介质流,它们分别向Byte 数组、和本地文件中写入数据。
    PipedOutputStream 是向与其它线程共用的管道中写入数据,
    ObjectOutputStream 和所有FilterOutputStream的子类都是装饰流。具体例子跟InputStream是对应的。

    复制代码
    public static void main(String[] args) throws IOException {
      File f = new File("aaa.txt"); // 定位文件位置
      OutputStream out = new FileOutputStream(f); // 创建字节输出流连接到文件
      String str = "hhhhhhh"; 
      byte[] b = str.getBytes(); //讲数据存入byte数组
      out.write(b); //写数据 
      out.close(); //关闭流
    }
    复制代码

    加入字节缓冲输入流,提高了读取效率

    复制代码
    public static void main(String[] args) throws IOException {
      File f = new File("aaa.txt"); // 定位文件位置
      OutputStream out = new FileOutputStream(f); // 创建字节输出流连接到文件
      BufferedOutputStream bos=new BufferedOutputStream(out);
      String str = "hhhhhhh"; 
      byte[] b = str.getBytes(); //讲数据存入byte数组
      bos.write(b); //写数据 
      bos.close(); //关闭缓冲流
      out.close(); //关闭流
    }
    复制代码

    5.几个特殊的输入流类分析

    LineNumberInputStream
    主要完成从流中读取数据时,会得到相应的行号,至于什么时候分行、在哪里分行是由改类主动确定的,并不是在原始中有这样一个行号。在输出部分没有对应的部分,我们完全可以自己建立一个LineNumberOutputStream,在最初写入时会有一个基准的行号,以后每次遇到换行时会在下一行添加一个行号,看起来也是可以的。好像更不入流了。

    PushbackInputStream
    其功能是查看最后一个字节,不满意就放入缓冲区。主要用在编译器的语法、词法分析部分。输出部分的BufferedOutputStream 几乎实现相近的功能。

    StringBufferInputStream

    已经被Deprecated,本身就不应该出现在InputStream部分,主要因为String 应该属于字符流的范围。已经被废弃了,当然输出部分也没有必要需要它了!还允许它存在只是为了保持版本的向下兼容而已。

    SequenceInputStream
    可以认为是一个工具类,将两个或者多个输入流当成一个输入流依次读取。完全可以从IO 包中去除,还完全不影响IO 包的结构,却让其更“纯洁”――纯洁的Decorator 模式。

    三、字符流

    1.字符输入流Reader
    定义和说明:

    在上面的继承关系图中可以看出:Reader 是所有的输入字符流的父类,它是一个抽象类。
    CharReader、StringReader是两种基本的介质流,它们分别将Char 数组、String中读取数据。
    PipedReader 是从与其它线程共用的管道中读取数据。
    BufferedReader 很明显就是一个装饰器,它和其子类负责装饰其它Reader 对象。
    FilterReader 是所有自定义具体装饰流的父类,其子类PushbackReader 对Reader 对象进行装饰,会增加一个行号。
    InputStreamReader 是一个连接字节流和字符流的桥梁,它将字节流转变为字符流。FileReader可以说是一个达到此功能、常用的工具类,在其源代码中明显使用了将FileInputStream 转变为Reader 的方法。我们可以从这个类中得到一定的技巧。Reader 中各个类的用途和使用方法基本和InputStream 中的类使用一致。后面会有Reader 与InputStream 的对应关系。

    复制代码
    public static void main(String[] args) throws IOException {    
        File f = new File("aaa.txt"); // 定位文件位置
        char[] ch = new char[100]; //定义一个数组,用来存放读入的数据
        Reader read = new FileReader(f); //创建字符输入流连接到文件
        int count = read.read(ch); //读操作
        read.close(); //关闭流
        System.out.println("读入的长度为:" + count);
        System.out.println("内容为" + new String(ch, 0, count));
    }
    复制代码

    加入缓冲流 提高效率。

    复制代码
    public static void main(String[] args) throws IOException {    
        File f = new File("aaa.txt"); // 定位文件位置
        char[] ch = new char[100]; //定义一个数组,用来存放读入的数据
        Reader read = new FileReader(f); //创建字符输入流连接到文件
        BufferedReader bfr=new BufferedReader(read); //创建缓冲流
        int count = bfr.read(ch); //读操作
        bfr.close(); //关闭缓冲流
        read.close(); //关闭流
        System.out.println("读入的长度为:" + count);
        System.out.println("内容为" + new String(ch, 0, count));
    }
    复制代码

    2.字符输出流Writer

    定义和说明:

    在上面的关系图中可以看出:Writer 是所有的输出字符流的父类,它是一个抽象类。
    CharArrayWriter、StringWriter 是两种基本的介质流,它们分别向Char 数组、String 中写入数据。
    PipedWriter 是向与其它线程共用的管道中写入数据,
    BufferedWriter 是一个装饰器为Writer 提供缓冲功能。
    PrintWriter 和PrintStream 极其类似,功能和使用也非常相似。
    OutputStreamWriter 是OutputStream 到Writer 转换的桥梁,它的子类FileWriter 其实就是一个实现此功能的具体类(具体可以研究一SourceCode)。功能和使用和OutputStream 极其类似。

    复制代码
    public static void main(String[] args) throws IOException {    
        File f=new File("aaa.txt"); // 定位文件位置
        Writer out =new FileWriter(f); //创建字符输出流连接到文件
        String str="哈哈哈哈哈哈"; 
        out.write(str); //写操作 
        out.close(); //关闭流    
    }
    复制代码

    加入缓冲流 提高效率。

    复制代码
    public static void main(String[] args) throws IOException {    
        File f=new File("aaa.txt"); // 定位文件位置
        Writer out =new FileWriter(f); //创建字符输出流连接到文件
        BufferedWriter bfw =new BufferedWriter(out); //创建缓冲流
        String str="哈哈哈哈哈哈"; 
        bfw.write(str); //写操作 
        bfw.close(); //关闭缓冲流
        out.close(); //关闭流
    }
    复制代码

    四、字符流与字节流转换

    转换流的特点:
    (1)其是字符流和字节流之间的桥梁
    (2)可对读取到的字节数据经过指定编码转换成字符
    (3)可对读取到的字符数据经过指定编码转换成字节
    何时使用转换流?
    当字节和字符之间有转换动作时;
    流操作的数据需要编码或解码时。
    具体的对象体现:
    InputStreamReader:字节到字符的桥梁
    OutputStreamWriter:字符到字节的桥梁
    这两个流对象是字符体系中的成员,它们有转换作用,本身又是字符流,所以在构造的时候需要传入字节流对象进来。

    复制代码
    /**
    * 将字节输出流转化为字符输出流
    * */
    public static void main(String[] args) throws IOException { File file=new File("aaa.txt"); Writer out=new OutputStreamWriter(new FileOutputStream(file)); out.write("hello"); out.close(); }
    复制代码
    复制代码
    /**
    * 将字节输入流变为字符输入流
    * */
    
    public static void main(String[] args) throws IOException {
        File file=new File("aaa.txt"); 
        Reader read=new InputStreamReader(new FileInputStream(file));
        char[] b=new char[100];
        int len=read.read(b);
        System.out.println(new String(b,0,len));
        read.close();
    }
    复制代码
  • 相关阅读:
    js 树型数据 转 数组
    js 数组转树型结构数据
    计算 手机端页面高度和宽度
    解密优酷智能生产技术,看 AI 赋能内容数字化
    从 FFmpeg 性能加速到端云一体媒体系统优化
    导播上云,把 “虚拟演播厅” 搬到奥运村
    揭秘阿里云 RTS SDK 是如何实现直播降低延迟和卡顿
    迈入 8K 时代,AI 驱动超高清 “视” 界到来
    千亿级市场赛道,阿里云视频云拿下 “三连冠”
    50 亿观众的 “云上奥运”,顶级媒体背后的数智化力量
  • 原文地址:https://www.cnblogs.com/zhaohongtian/p/6807384.html
Copyright © 2011-2022 走看看