Java中的IO

1、概念

IO(Input、Output)表示输入与输出。

Java 1.0中IO是流式IO,只能一个个字节的处理数据,所以也叫Stream IO,其响应是阻塞式的。

Java 1.4中的NIO(non-blocking)是非阻塞式,其处理数据是以Buffer的方式。

2、IO相关类

java的io相关接口和类都在java.io包下,最顶层最常用的抽象类有四个,分别是InputStream、OutputStream、Reader、Writer,其关系图如下:

InputStream的子类很多,例如常见的FileInputStream、ByteArrayInputStream、PipedInputStream、FilterInputStream、ObjectInputStream,Input和Output成对出现,OutputStream同理。

Reader的子类也很多,BufferedReader、CharArrayReader、FileReader、FilterReader、InputStreamReader、PipedReader、StringReader,Reader和Writer成对出现,Writer同理。

3、分类

按字节和字符分:InputStream和OutputStream处理字节流,Reader和Writer处理字符流。

从介质上分有三种:数组ByteArrayInputStream、文件FileInputStream和字符串,有各自的使用场景,不是所有的数据都是以文件的形式存在,比如内存中的数据就是以字节数组的形式存在,可能是图片、视频等等。

总结:纯文本数据用Reader和Writer处理,非纯文本用InputStream和OutputStream处理,文件用FileInputStream处理,内存用ByteArrayInputStream处理。

4、使用场景

下面简述常用类的使用场景

  • FileInputStream:在处理文件时会用到,不论是处理文本文件还是二进制文件都可以,一般搭配字节数组做缓冲区,类似于BufferInputStream。
  • ByteArrayInputStream:在内存中创建一个字节数组缓冲区,用来处理内存中存在的数据。
  • PipedInputStream:一般用来处理线程间的通信。因为现在有了更好的方式处理线程间通信的,比如BlockingQueue,所以在实际开发中用的比较少。
  • FilterInputStream:本身没有新增什么功能,就是对于InputStream的外层封装,用于给其他类去继承。
  • ObjectInputStream:顾名思义可以将流和对象进行转换,例如将自定义的对象序列化后保存到一个文件,将一个文件读取的流解析成一个对象。
  • BufferedInputStream:本质就是将其他流存到了自己的缓冲数组里面,后续的操作从自身数组中读取。其逻辑是从其他流里面读取固定长度的数据,存到自身的字节数组,然后读取的时候先从自身的数组里读,当数组里的数据读完了,就会重新从流里缓存,直到把数据全部读完,相当于一个中转站。其继承了FilterInputStream,扩展了能力,用法和FileInputStream一致,当FileInputStream使用的缓存数组大小设置为8192时,和默认的BufferedInputStream没有区别。
  • BufferedReader:和BufferedInputStream类似,构造方法是传入一个Reader,专门处理字符流。
  • FilterReader:和FilterInputStream类似,就是给其他的类继承,好扩展功能。
  • InputStreamReader:继承了Reader,专门将字节流转成字符流,是一个转换类,其构造方法入参就是InputStream。
  • FileReader:继承了InputStreamReader,其实就是简化使用,不然得先从File获取字节流,再把字节流转换成字符流使用,FileReader直接从文件获取字符流,构造方法入参有两个,一个是文件路径,一个是文件。
  • PipedReader:和PipedInputStream类似,用来处理线程间的通信。例如一个线程获取键盘输入,一个线程输出内容到控制台。
  • CharArrayReader:其数据源是一个字符数组,讲一个字符数组作为输入源。
  • StringReader:数据源是一个字符串,结合标记和重置方法,可以读取字符串任意位置的字符。

5、常用示例代码

  • FileInputStream和FileOutputStream,复制文件A到文件B
/**
 * 复制原文件到一个新的文件
 *
 * @param file    原文件
 * @param newFile 新文件
 * @throws IOException
 */
private void copyFileByFileStream(File file, File newFile) throws IOException {
    if (newFile.exists() || newFile.createNewFile()) {
        try (OutputStream outputStream = new FileOutputStream(newFile); InputStream inputStream = new FileInputStream(file)) {
            //设置缓冲区大小为2Kb
            byte[] bytes = new byte[2048];
            //记录缓冲区存储的数据大小
            int length;
            //循环从inputStream读取最多2kb的数据,直到取完所有的数据
            while ((length = inputStream.read(bytes)) != -1) {
                //将缓冲区实际保存的数据写入outputStream
                outputStream.write(bytes, 0, length);
            }
        }
    }
}
  • BufferedInputStream和BufferedOutputStream,复制文件A到文件B
/**
 * 复制原文件到一个新的文件
 *
 * @param file    原文件
 * @param newFile 新文件
 * @throws IOException
 */
private static void copyFileByBufferStream(File file, File newFile) throws IOException {
    if (newFile.exists() || newFile.createNewFile()) {
        try (BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(newFile));
             BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {
            //设置缓冲区大小为2Kb
            byte[] bytes = new byte[2048];
            //记录缓冲区存储的数据大小
            int length;
            //循环从inputStream读取最多2kb的数据,直到取完所有的数据
            while ((length = inputStream.read(bytes)) != -1) {
                //将缓冲区实际保存的数据写入outputStream
                outputStream.write(bytes, 0, length);
            }
        }
    }
}
  • BufferedReader打印文本文件内容,入参是InputStreamReader(将字节流转成字符流)
/**
 * BufferedReader只能处理字符流
 * InputStreamReader是字节流转字符流的桥梁
 * 所以需要用到InputStreamReader将字节流转成字符流
 *
 * @param file
 * @throws IOException
 */
private static void testFileInputStream(File file) throws IOException {
    try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
        StringBuilder builder = new StringBuilder();
        String str;
        while ((str = reader.readLine()) != null) {
            builder.append(str).append(System.getProperty("line.separator"));
        }
        System.out.println(builder);
    }
}
  • BufferedReader打印文本文件内容,入参是FileReader(将文件转成字符流)
/**
 * BufferedReader只能处理字符流
 * FileReader继承了InputStreamReader,其提供了将文件直接转换成字符流的构造方法
 *
 * @param file
 * @throws IOException
 */
private static void testFileReader(File file) throws IOException {
    try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
        StringBuilder builder = new StringBuilder();
        String str;
        while ((str = reader.readLine()) != null) {
            builder.append(str).append(System.getProperty("line.separator"));
        }
        System.out.println(builder);
    }
}
posted @ 2023-03-10 17:56  浪迹天涯的派大星  阅读(84)  评论(0编辑  收藏  举报