聊聊什么是IO流

news2024/11/16 23:38:53

目录

  • Java IO
    • IO 基础
      • Java IO 流了解吗?
    • IO 设计模式
      • 1、装饰器模式
      • 2、适配器模式
      • 适配器模式和装饰器模式有什么区别呢?
      • 3、工厂模式
      • 4、观察者模式
    • IO 模型
      • 有哪些常见的 IO 模型?
        • BIO(Blocking I/O)
        • NIO (Non-blocking/New I/O)
        • AIO (Asynchronous I/O)
      • BIO、NIO、AIO 有什么区别?
    • 参考

Java IO

IO 基础

Java IO 流了解吗?

IO 即 Input/0utput ,输入和输出。数据输入到计算机内存的过程即输入,反之输出到外部存储 (比如数据库,文件,远程主机)的过程即输出。

数据传输过程类似于水流,因此称为 IO 流。

  • IO 流在 java 中分为输入流输出流
  • 而根据数据的处理方式又分为字节流字符流

Java IO 流的 40 多个类都是从如下 4 个抽象类基类中派生出来的:

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流

IO 设计模式

1、装饰器模式

装饰器模式是一种结构型设计模式,允许在运行时动态地将责任附加到对象上。

是一种通过组合替代继承来扩展原始类的功能,可以在不改变原有对象的情况下增强其功能的模式。

// 输入
// 将FileInputStream对象 装饰 成了一个带有缓冲区的输入流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(fileName));
// 将带有缓冲区的输入流对象 再次装饰 成了一个能够处理ZIP文件的输入流对象
ZipInputStream zis = new ZipInputStream(bis);

// 输出
// 将FileOutputStream对象 装饰 成了一个带有缓冲区的输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));
// 将带有缓冲区的输出流对象 再次装饰 成了一个能够处理ZIP文件的输出流对象。
ZipOutputStream zipOut = new ZipOutputStream(bos);

其中 BufferedInputStream、ZipInputStream、BufferedOutputStream 和 ZipOutputStream 都是 Java 中的装饰器类。

2、适配器模式

可以用于将不兼容的类或接口转换为兼容的类或接口,从而使它们能够协同工作。

适配器模式中存在被适配的对象或者类称为 适配者(Adaptee) ,作用于适配者的对象或者类称为适配器(Adapter)

// InputStreamReader 是适配器,用于将 FileInputStream 实现的字节流接口适配成字符流接口
InputStreamReader isr = new InputStreamReader(new FileInputStream(fileName), "UTF-8");
// BufferedReader 增强 InputStreamReader 的功能(装饰器模式)
BufferedReader bufferedReader = new BufferedReader(isr);

适配器模式和装饰器模式有什么区别呢?

适配器模式和装饰器模式虽然都属于结构型设计模式,但是它们的设计目的和实现方式有所不同。

设计目的

  1. 适配器模式(Adapter Pattern)的设计目的是:将一个类的接口转换为客户端所期望的另一个接口,以满足客户端的需求。适配器模式通常用于解决接口不兼容的问题,它通过一个适配器来将一个类的接口转换为另一个接口,使得客户端可以像调用另一个接口一样来调用原来的接口。适配器模式通常是在已有的系统中进行接口升级或者系统集成时使用的。
  2. 装饰器模式(Decorator Pattern)的设计目的是:在不改变原有对象的基础上,动态地给对象添加一些新的功能。装饰器模式通常用于解决类的功能扩展问题,它通过在原有对象的基础上添加一个装饰器来为对象添加新的功能,使得客户端可以在不改变原有对象的情况下使用新的功能。装饰器模式通常是在需要为一个对象动态地添加一些功能时使用的。

实现方式

适配器模式通常是通过一个适配器类来转换接口,而装饰器模式通常是通过继承或者组合的方式来实现功能的添加

  • 装饰器类需要跟原始类继承相同的抽象类或者实现相同的接口。(同一个父类,字节流 – 字节流)
  • 适配器和适配者两者不需要继承相同的抽象类或者实现相同的接口。(不同的父类,字符流 – 字节流)

3、工厂模式

Java IO 中的工厂模式指的是:通过工厂类来创建不同类型的输入输出流对象。从而实现更加灵活的 IO 操作。

常用的 IO 工厂模式有 InputStreamFactory、OutputStreamFactory、ReaderFactory 和 WriterFactory 等。

代码示例如下:

  1. 首先创建四个工厂对象:InputStreamFactory、OutputStreamFactory、ReaderFactory 和 WriterFactory,分别用于创建输入流、输出流、字符输入流和字符输出流。
  2. 然后,通过调用它们的 create 方法,创建了对应的输入流对象和输出流对象
  3. 最后,使用创建的输入流对象和输出流对象,对文件进行读写操作
public class IOFactoryDemo {
    public static void main(String[] args) {
        // 创建输入流工厂对象
        InputStreamFactory inputStreamFactory = new FileInputStreamFactory();

        // 创建输出流工厂对象
        OutputStreamFactory outputStreamFactory = new FileOutputStreamFactory();

        // 创建字符输入流工厂对象
        ReaderFactory readerFactory = new FileReaderFactory();

        // 创建字符输出流工厂对象
        WriterFactory writerFactory = new FileWriterFactory();

        // 创建文件输入流对象
        InputStream inputStream = inputStreamFactory.createInputStream("C:\\myfiles\\input.txt");

        // 创建文件输出流对象
        OutputStream outputStream = outputStreamFactory.createOutputStream("C:\\myfiles\\output.txt");

        // 创建字符输入流对象
        Reader reader = readerFactory.createReader("C:\\myfiles\\input.txt");

        // 创建字符输出流对象
        Writer writer = writerFactory.createWriter("C:\\myfiles\\output.txt");

        // 从文件输入流中读取数据
        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 向文件输出流中写入数据
        try (BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream)) {
            String data = "Hello, world!";
            byte[] bytes = data.getBytes();
            bufferedOutputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 从字符输入流中读取数据
        try (BufferedReader bufferedReader = new BufferedReader(reader)) {
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 向字符输出流中写入数据
        try (BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
            String data = "Hello, world!";
            bufferedWriter.write(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用工厂模式的好处是什么?

通过工厂模式创建输入输出流对象,可以避免直接使用具体的类来创建对象,降低了客户端和具体类的耦合度,提高了系统的灵活性和扩展性。此外,工厂方法还可以对输入输出流对象进行统一管理和控制,从而实现一些特定的功能,如数据压缩、加密等。

4、观察者模式

IO 观察者模式是一种设计模式,用于监控文件或目录的变化

在 Java 中,可以使用 java.nio.file 包中的 WatchService 类来实现 IO 观察者模式。

WatchService 类充当观察者,用于监控指定目录中的文件或子目录的变化。当目录中的文件或子目录发生变化时,WatchService通过 Path 事件通知注册的观察者

具体地说,使用 WatchService 实现 IO 观察者模式的步骤如下:

  1. 创建一个 WatchService 对象,通过 Path 对象的 register() 方法将其注册到需要监控的目录中。

  2. 创建一个线程,不断从 WatchService 对象中获取事件,并处理这些事件。

  3. WatchService 对象检测到目录中的文件或子目录发生变化时,会生成一个 Path 事件,并将其添加WatchService 对象的事件队列中。

  4. 在处理事件的线程中,可以通过 WatchEvent 对象获取事件类型、事件发生的路径等信息,并根据这些信息进行相应的处理

/**
 * 文件观察者类,用于监测指定目录中文件的变化
 */
public class FileWatcher implements Runnable {
    private Path path;              // 目录路径
    private WatchService watchService;  // WatchService对象用于监测目录中文件的变化

    /**
     * 构造函数,创建一个FileWatcher对象
     * @param path 目录路径
     * @throws IOException 抛出IO异常
     */
    public FileWatcher(Path path) throws IOException {
        this.path = path;
        // 获取默认的WatchService对象
        this.watchService = FileSystems.getDefault().newWatchService();
        // 注册监测事件类型
        this.path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY);
    }

    /**
     * run方法,用于启动监测线程
     */
    @Override
    public void run() {
        try {
            while (true) {
                // 获取WatchKey对象,它代表了被监测的目录中的事件队列
                WatchKey key = watchService.take();
                // 遍历事件队列
                for (WatchEvent<?> event : key.pollEvents()) {
                    // 输出事件类型和受影响的文件名
                    System.out.println("Event kind: " + event.kind() + ". File affected: " + event.context() + ".");
                }
                // 重置WatchKey对象,以便继续监测
                key.reset();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * main方法,用于启动文件监测程序
     */
    public static void main(String[] args) throws IOException {
        // 创建监测的目录路径
        Path path = Paths.get("/path/to/monitor");
        // 创建FileWatcher对象
        FileWatcher fileWatcher = new FileWatcher(path);
        // 创建监测线程,并启动
        Thread thread = new Thread(fileWatcher);
        thread.start();
    }
}

IO 观察者模式可以用于监控文件或目录的变化,从而实现一些特定的功能,如自动备份、自动同步等。在实际开发中,IO 观察者模式可以提高代码的可维护性和可扩展性,使得代码更加灵活。

IO 模型

有哪些常见的 IO 模型?

Java 中有 3 种常见 IO 模型:

BIO(Blocking I/O)

BIO 属于同步阻塞 IO 模型

同步阻塞 IO 模型中,应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。

在这里插入图片描述

NIO (Non-blocking/New I/O)

NIO 属于同步非阻塞 IO 模型

NIO(New I/O)是 Java NIO(New Input/Output)API 的简称,是 Java SE 1.4 中引入的一组新的 I/O API,用于替代 Java 标准 I/O API(java.io 包)中的一部分功能。

NIO 提供了一种基于通道(Channel)和缓冲区(Buffer)的 I/O 模型,相较于传统的基于流的 I/O 模型,它具有更高的性能和更好的扩展性。

  • 通道表示数据源与目标之间的连接,可以用于读取和写入数据。
  • 缓冲区则是存储数据的区域,数据通过缓冲区进行传输。
    在这里插入图片描述

在同步非阻塞I/O模型中,应用程序发起 read 调用后(轮询操作),线程不会被阻塞。相反,线程会立即返回,并继续执行后续的操作,而不必等待数据从内核空间拷贝到用户空间。

通过不断发起 read 调用来检查是否有新的数据可用

但是它可以通过多路复用技术来实现高效的 IO 操作,减少无效的系统调用,减少了对 CPU 资源的消耗。

IO 多路复用模型中,线程首先发起 select 调用,询问内核数据是否准备就绪,等内核把数据准备好了,用户线程再发起 read 调用。read 调用的过程(数据从内核空间 -> 用户空间)还是阻塞的。
在这里插入图片描述

AIO (Asynchronous I/O)

AIO 是异步 IO 模型

异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
在这里插入图片描述

BIO、NIO、AIO 有什么区别?

它们主要的区别在于数据的读取和处理方式不同。

  1. BIO(Blocked IO):**BIO 是同步阻塞 I/O 模型。**在该模型下,所有的 I/O 操作都是阻塞的,即当一个线程在进行 I/O 操作时,它会一直等待直到数据准备就绪或者发生异常。(只会发起一次 read 调用,但会阻塞)

    BIO 模型适用于连接数比较少且通信线程比较短的场景,例如传统的客户端/服务器模型。

  2. NIO(Non-Blocked IO):**NIO 是同步非阻塞 I/O 模型。**在该模型下,所有的 I/O 操作都是非阻塞的,即当一个线程在进行 I/O 操作时,它会立即返回一个特定的状态(通常是非阻塞状态,如EAGAIN或EWOULDBLOCK),表示当前没有可用的数据,而不会等待数据准备就绪。(会一直发起 read 调用)

    NIO 模型适用于连接数比较多且通信线程比较长的场景,例如聊天室和在线游戏。

  3. AIO(Asynchronous IO):**AIO 是异步非阻塞 I/O 模型。**在该模型下,所有的 I/O 操作都是异步的,即当一个线程在进行 I/O 操作时,它不需要等待数据准备就绪,而是通过回调函数的方式来处理数据。(只会发起一次 read 调用)

    AIO 模型适用于连接数非常多且通信线程比较长的场景,例如高性能的网络服务器。

总的来说,

  • BIO 模型的开销比较大,但是编程模型比较简单;(性能较低)
  • NIO 模型的开销比较小,但是编程模型比较复杂;(性能较高)
  • AIO 模型相对于 NIO 模型来说,编程模型更为简单,但是在性能方面与 NIO 模型相当或者略逊一筹。(综合型)

参考

Java基础常见面试题总结(下)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1276854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java包(package)

1、概念 为了更好的组织类&#xff0c;用于区别类名的命名空间&#xff0c;其实就是基于工程的一个文件路径&#xff0c;如&#xff1a; 2、作用 三个作用&#xff1a; 1&#xff09;区分相同名称的类。 2&#xff09;能够较好地管理大量的类。 3&#xff09;控制访问范围。 在…

网站实现验证码功能

一、验证码 一般来说&#xff0c;网站在登录的时候会生成一个验证码来验证是否是人类还是爬虫&#xff0c;还有一个好处是防止恶意人士对密码进行爆破。 二、流程图 三、详细说明 3.1 后端生成验证码 Override public Result<Map<String, String>> getVerifica…

国内哪个超声波清洗机品牌比较好?质量好超声波清洗机总结

近年来超声波清洗机可以说是非常火爆&#xff0c;可以清洗化妆刷、眼镜、牙套等等一些小物件&#xff0c;大物件物品可以入手大型超声波清洗机&#xff0c;总之现在超声波清洗机已经衍生到可以在家使用&#xff0c;不再是在眼镜店看到它的身影或者是一些工业领域上&#xff0c;…

第二节:服务拆分(案例)

一、服务拆分注意事项 1.1 拆分原则 每个微服务&#xff0c;不要重复开发相同业务&#xff08;例如在单体项目中用到了一个查询&#xff0c;这个查询功能能够查询出订单信息、商品信息、用户信息&#xff0c;那么在拆分微服务时就不要将其写在一起了&#xff0c;订单的微服务只…

1、RocketMQ源码分析(一)

RocketMQ简单介绍 RabbitMQ的底层是使用erlang语言编写的&#xff0c;不便分析其底层&#xff0c;RocketMQ作为原阿里下经历阿里双十一严格考验的中间件&#xff0c;同时也是使用我们熟悉的java语言编写&#xff0c;我们先把入门的基础必备了解透&#xff0c;然后在去分析源码…

基于WebSocket实现客户聊天室

目录 一、实现聊天室原理 二、聊天室前端代码 三、聊天室后端代码&#xff08;重点&#xff09; 四、聊天室实现效果展示 一、实现聊天室原理 1.1 介绍websocket协议 websocket是一种通信协议&#xff0c;再通过websocket实现弹幕聊天室时候&#xff0c;实现原理是客户端首…

使用K-means把人群分类

1.前言 K-mean 是无监督的聚类算法 算法分类&#xff1a; 2.实现步骤 1.数据加工&#xff1a;把数据转为全数字&#xff08;比如性别男女&#xff0c;转换为0 和 1&#xff09; 2.模型训练 fit 3.预测 3.代码 原数据类似这样(source&#xff1a;http:img-blog.csdnimg.cn…

vmware 安装 AlmaLinux OS 8.6

选择系统镜像 选择镜像 选择安装位置和修改名称 可以自定义硬件&#xff0c;也可以不选择&#xff0c;后面可以再设置 自定义硬件可以设置内存和cpu等信息 安装虚拟机系统 密码如果简单的话需要点击两次done 才能保存

集成开发环境PyCharm的使用【侯小啾python领航计划系列(三)】

集成开发环境 PyCharm 的使用【侯小啾python领航计划系列(三)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

Stable Diffusion AI绘画系列【10】:AI眼中的美丽清晨

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

【数电笔记】卡诺图绘制(逻辑函数的卡诺图化简)

目录 说明&#xff1a; 最小项卡诺图的组成 1. 相邻最小项 2. 卡诺图的组成 2.1 二变量卡诺图 2.2 三表变量卡诺图 2.3 四变量卡诺图 3. 卡诺图中的相邻项&#xff08;几何相邻&#xff09; 说明&#xff1a; 笔记配套视频来源&#xff1a;B站 最小项卡诺图的组成 1. …

算法通关村第十四关-青铜挑战认识堆

大家好我是苏麟 , 今天带大家认识认识堆 . 堆 堆是将一组数据按照完全二叉树的存储顺序&#xff0c;将数据存储在一个一维数组中的结构。 堆有两种结构&#xff0c;一种称为大顶堆&#xff0c;一种称为小顶堆 : 大顶堆 大顶堆的任何一个父节点的值&#xff0c;都大于或等于…

nginx设置用户密码

1.官网 https://nginx.org/en/docs/http/ngx_http_auth_basic_module.html2.语法 3.创建密码 [rootlocalhost ~]# yum install httpd-tools -y4.创建密码文件 完毕&#xff01; [rootlocalhost ~]# htpasswd -b -c /etc/nginx/auth-passwd xp xp666-c 创建passwdfile &#…

免费使用优彩云采集器,3分钟学会优彩云采集器使用【2023最新】

如何高效地采集并聚合原创内容成为了一项关键任务&#xff1f;在这个背景下&#xff0c;本文将深入研究优彩云采集和147SEO采集&#xff0c;实现原创文章采集。 147SEO采集器 对于许多从业者而言&#xff0c;147SEO采集并不陌生。作为一款专注于原创内容采集的工具&#xff0c…

avue页面布局 api 引用

展示 index.vue <template><basic-container><avue-crud :option"option":table-loading"loading":data"data":page"page":permission"permissionList":search.sync"search":before-closebefore…

【LeeCode】24. 两两交换链表中的节点

给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff1a;[2,1,4…

【LeeCode】19.删除链表的倒数第N个节点

给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5] 示例 2&#xff1a; 输入&#xff1a;head [1], n 1 输出&#xff1a;[] 示例 3&#xf…

4款非常牛的Linux终端应用,thefuck尤其突出

这篇文章向大家介绍了4款非常棒且非常有用的Linux终端应用程序&#xff0c;可以使我们的日常命令操作更加高效。这些工具不仅可以让你在同事面前炫耀一番&#xff0c;而且它们还提供了实用且美观的功能。 第一款&#xff1a;thefuck 你是不是经常在终端敲错命令&#xff1f;敲…

virtualbox中windows11开机自动登录设置

笔者在实际应用过程中&#xff0c;使用了Vritualbox系统安装windows11&#xff0c;然后在windows11中部署了相关应用&#xff0c;需要在开机之后自动启动该应用。 但是实际测试发现&#xff0c;必须windows11的用户登录该系统之后该应用才能启动&#xff0c;否则尽管windows11…

Beta冲刺随笔-DAY6-橘色肥猫

这个作业属于哪个课程软件工程A这个作业要求在哪里团队作业–站立式会议Beta冲刺作业目标记录Beta冲刺Day6团队名称橘色肥猫团队置顶集合随笔链接Beta冲刺笔记-置顶-橘色肥猫-CSDN博客 文章目录 SCRUM部分站立式会议照片成员描述 PM报告项目程序&#xff0f;模块的最新运行图片…