JAVA I/O流 字符流和字节流、节点流和处理流(包装流、过滤流)、缓冲流

一、相关概念

I/O流: Input/Output Stream,文件输入输出流。

1、分类:

  • 输入流 和 输出流:(站在程序的角度) 根据读写操作/数据流动的方向区分。

    • 其中输入流就是指读取文件中的内容输入到程序中的流,也就是读文件。
    • 其中输出流就是指将程序中的内容输出到文件中的流,也就是写文件。
  • 字节流 和 字符流:根据读写操作的基本单位分。

    • 参考: https://blog.csdn.net/yogima/article/details/78705411
    • 其中字节流就是指以字节为基本单位进行读写的流,可以处理任何文件。字节(8位 )
    • 字符流就是指以字符(2个字节)为基本单位进行读写的流,只能处理文本文件。字符(16位)。Reader和Writer
  • 数据传输方式:

    • 节点流(Node Stream 直接和文件打交道)
    • 包装流(又称处理流、过滤流、缓冲流)程序和文件之间有管道,不直接接触。
  • 缓冲流:

    • 什么是缓冲流:参考 https://www.cnblogs.com/aademeng/articles/10880511.html
    • 意义:在内存与硬盘之间创建一个大小合适的缓冲区,当内存和硬盘进行数据访问时,能提高访问硬盘的次数,提高效率。
      • 是一个包装流,目的起缓冲作用.包括:
      • BufferedInputStream:字节输入缓冲流
      • BufferedOutputStream:字节输出缓冲流
      • BufferedReader:字符输入缓冲流
      • BufferedWriter::字符输出缓冲流
        字节流图解
        字符流
        字符流套接

区别和联系

1、节点流和处理流

  • (1)节点流是低级流,直接跟数据源相接。

    • 处理流(也叫包装流)把节点流包装了一层,属于修饰器设计模式,不会直接与数据源相连,通过处理流来包装节点流既可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出。
  • (2)处理流的功能主要体现在以下两个方面:

    • 1.性能的提高:主要以增加缓冲的方式来提高输入输出的效率。
    • 2.操作的便捷:处理流可能提供了一系列便捷的方法来一次输入输出大批量的内容,而不是输入/输出一个或多个水滴处理流可以嫁接在任何已存在的流的基础上。
  • 节点流(Node Stream) :直接与原始数据存在的特定介质(如磁盘文件或其他外部设备、内存某区域或其他程序)打交道的流,在流的序列中离程序最远。

  • 过滤流 (Filter Stream):使用其它的流作为输入源或输出目的地,对流中的数据提供进一步处理的流。其他的流可以是节点流,也可以是另一种过滤流。过滤流不能单独使用。

  • 一个输入流链或输出流链中一定有且只有一个节点流;可以没有,也可以有多个过滤流。

2、字符流和字节流

代码

  • 1、字节流: InputStream和OutputStream
    • InputStream
      InputStream是抽象类,不能直接用new InputStream()构造实例。 FileInputStream是InputStream的子类,可以生成实例。 FileInputStream有三个构造方法,最常用的构造方法如下:
      
      Public FileInputStream(String fileName) throws FileNotFoundException
      Public FileInputStream(File file) throws FileNotFoundException
      //fileName用来指定输入文件名及其路径,file是一个File对象
      
      InputStream类的read()方法:逐字节以二进制的原始方式读取数据
      
      public int read();//读入一个字节,-1表示无
      public int read(byte b[]);//返回读入的字节数
      public int read(byte[] b,int off.int len);//返回从某个位置开始制定长度的字节数
      
    • OutputStream
      构造方法:
      OutputStream是抽象类,不能直接用new OutputStream()构造实例。 FileOutputStream是OutputStream的子类,可以生成实例。 FileOutputStream最常用的构造方法如下:
      
      Public FileOutputStream(String name) throws FileNotFoundException
      Public FileOutputStream(String name,boolean append) throws FileNotFoundException
      //Name用来指定输入文件名及其路径,append为true时数据将添加到文件已有内容的末尾
      
      常用方法:
      //写一个字节
      void write( int ) throws IOException 
      //关闭输出流
      void close( ) throws IOException 
      //强行将缓冲区的数据写到目的地。
      void flush( ) throws IOException 
      //写一个字节数组
      void write(byte[ ] b) throws IOException 
          void write(byte[ ] b, int offset, int length ) throws IOException 
      
  • 利用字节流复制文件
import java.io.*;
class CopyAFile 
{
    public static void main(String[] args) 
    {
        InputStream in;
        OutputStream out;
        try
        {
            in=new FileInputStream("test.txt");
            out=new FileOutputStream("copyResult.txt");
//          out=new FileOutputStream("copyResult.txt",true);
            int aByte;
            aByte=in.read();
            while (aByte!=-1)
            {
                out.write(aByte);
                aByte=in.read();
            }
            in.close();
            out.close();
            System.out.println("文件复制完毕。test.txt已经复制到copyResult.txt中。");
        }
        catch(FileNotFoundException e)
        {
            System.out.println("当前目录下文件test.txt不存在!");
        }
        catch(IOException e)
        {
            System.out.println("发生输入输出错误!");
        }
    }
}
  • 2、字符流: Reader和Writer

    • 字符(16位)流不一定对应两个字节,要考虑到编码问题。
    • 只能操作文本文件。
    Reader类读取的是字符,而不是字节。 
    Reader类的重要方法read():
    
    public int read();//需要将int转为char
    public int read(char b[]);
    public int read(char[] b,int off,int len)
    
  • 3、滤流和节点流的套接:

InputStream in;
in=new BufferedInputStream(new FileInputStream("test.txt"));
BufferedReader in = new BufferedReader(new FileReader(file));

BufferedReader in2 = new BufferedReader(new inputStreamReader(new FileInputStream(file),"utf-8"));
s = in2.readLine();

套接流

嵌套的IO流关闭的问题

参考:https://blog.csdn.net/menghuanzhiming/article/details/77945822

  • 当然完全可以只关闭处理流,不用关闭节点流。处理流关闭的时候,会调用其处理的节点流的关闭方法

一般情况下是:

  • 先打开的后关闭,后打开的先关闭;
  • 另一种情况:看依赖关系,如果流a依赖流b,应该先关闭流a,再关闭流b
  • 例如处理流a依赖节点流b,应该先关闭处理流a,再关闭节点流b
  • 如果将节点流关闭以后再关闭处理流,会抛出IO异常;

猜你喜欢

转载自blog.csdn.net/xielong0509/article/details/100562001