IO流(2)-缓冲流

news2024/9/20 18:17:43

1. 缓冲流的简单介绍

我们上贴说到了 FileInputStream,FileOutputStream,FileReader,FileWriter。 

其实这四个流,我们通常把它叫做原始流,它们是比较偏底层的;而今天我们要说的四个缓冲流,如下图所示,叫包装流,也叫处理流,它们之间也有继承关系自下而上,并且它们都可以提高原始流读写数据的性能。

2. 为什么要用到缓冲流

我先来说一下为什么要用到字节缓冲流,我们来看下面这幅图。

现在有一个需求,将D盘下一个大小为 16KB 的文件拷贝到C盘,该怎么做?

如果我们采用原始的字节流或者字符流,我们首先定义一个大小为 1KB 的数组,然后通过输入流读取数据,将数据读取到字节数组中, 然后再使用输出流将数组中的数据写入到C盘,由于数据源大小为16KB,我们输入流需要读取16次,输出流同样也要输出16次,这样合计就是32次,非常消耗系统资源,那么有没有什么更好的解决方案呢,在不改变题目的前提下,让我们减少与磁盘的IO次数,提高程序整体的运行效率呢?

当然是有的,它就是我们接下来要说的缓冲流

3. 缓冲流是如何提高读写性能的?

如上图所示,缓冲流之所以能提高读写的性能,是因为如果我们使用缓存输入流,那么它就会在内存中开辟一处大小为8KB输入缓存区,缓存输出流也是同样的道理,它也会在内存中开辟一处大小为8KB的输出缓存区;

还拿刚才的例子来说,当我们读取文件时,这8KB的输入缓存区会直接读满数据源中8KB的资源,然后,我们的缓存输出流在输出时,会从这8KB的缓存区读取内容,读取到内容之后,再写入另外8KB的输出缓冲区,当输出缓存区满了之后,会一次性的将8KB的数据以下次写入硬盘,由于内存中的读写效率非常的高,所以时间可以忽略不计,我们只看从D盘到内存和从内存到C盘的次数.

16KB需要读取两次,也需要输出两次,共计四次。而我们使用之前输入流和输出流,需要读写32次,效率提高了8倍,可以说是极大地提高了读写效率。

我们下面来看一下源码就知道了

3.1 BufferedInputStream 源码

 上图是 BufferdInputStream 的源码类,这里定义了一个 int变量 大小为 8192,就是1024 * 8

 往下翻可以找到 BufferdInputStream 的构造方法,我们点击 this 查看

 可以看到这里它 new 了一个数组,size 就是我们刚才说的那个 int 值,如此看来就是new 了一个大小为 8KB 的字节数组。

3.2 BufferdOutputStream 源码

这里也是一样,8192 ,也为8KB,点击this 方法查看如下

它也是 new 了一个大小为 8KB 的字节数组。

3.3 BufferReader 源码

 以上即为 BufferdReader 的源码,可以看到它这里也是 new 了一个大小为 8KB 的字符数组

3.4 BufferWriter 源码

 以上为 BufferdWriter 的源码,也是定义了一个大小为 8BK 的字符数组。

总的来说,缓冲流能提高读写效率的原因,是因为它们会在内存开辟缓存空间,减少了与磁盘的IO次数,从而提高了读写效率。

4. BufferInputStream和BufferOutputStream

BufferdInputStream 和 BufferdOutputStream 的构造器如下所示,它们分别需要传入一个 InputStream 的对象 和 OutputStream 的对象。

刚才我们看源码也看到了,其实BufferedInputStream还有一个构造方法,我们可以自行传入一个数组的大小,如果不传入,默认为8KB,我们也可以重载该构造方法,自行传入,例如传入一个 1024 * 16 ,那么就是在内存中创建一个 16KB大小的 缓存输入流空间,其它流也是同样的道理。

我做一个简单的案例,还是从C盘拷贝一个文件到D盘,如下代码

public static void main(String[] args) {
        // 创建输入流对象
        InputStream is = null;
        // 创建输出流对象
        OutputStream os = null;
        // 创建字节缓冲输入流对象
        BufferedInputStream bis = null;
        // 创建字节缓冲输出流对象
        BufferedOutputStream bos = null;
        try {
            is = new FileInputStream("user-service/test.txt");
            os = new FileOutputStream("D:/test2.txt");
            bis = new BufferedInputStream(is);
            bos = new BufferedOutputStream(os);
            // 定义一个大小为 1024 的字节数组
            byte[] bytes = new byte[1024];

            // 定义一个长度变量,记录读取到的字节数量
            int length;
            // 定义循环读取文件内容
            while((length = bis.read(bytes)) != -1){
                // 将读取到的内容写入磁盘
                bos.write(bytes,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (bos != null)
                    bos.close();
                if (bis != null)
                    bis.close();
                if (os != null)
                    os.close();
                if (is != null)
                    is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

运行上述代码,得到如下结果,我们到D盘查看,可以看到拷贝成功

5. BufferedReader 与 BufferedWriter

BufferedReader 与 BufferedWriter 的构造器根字节缓冲输入流,字节缓冲输出流极其相似,都是要传入一个流对象,这里就不需要我做过多的赘述了,适用语法也半差不差;

在字符缓冲输入流中还新增了一个方法,可以一行一行的读取数据

在字符缓冲输出流中也新增了一个方法,换行操作

我们把刚才字节缓冲流的代码稍微改动一下仍然可以用,如下

public static void main(String[] args) {
        // 创建输入流对象
        Reader r = null;
        // 创建输出流对象
        Writer w = null;
        // 创建字节缓冲输入流对象
        BufferedReader br = null;
        // 创建字节缓冲输出流对象
        BufferedWriter bw = null;
        try {
            r = new FileReader("user-service/test.txt");
            w = new FileWriter("D:/test3.txt");
            br = new BufferedReader(r);
            bw = new BufferedWriter(w);
            // 定义一个大小为 1024 的字节数组
            char[] chars = new char[1024];

            // 定义一个长度变量,记录读取到的字节数量
            int length;

            // 定义循环读取文件内容
            while((length = br.read(chars)) != -1){
                // 将读取到的内容写入磁盘
                bw.write(chars,0,length);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if (bw != null)
                    bw.close();
                if (br != null)
                    br.close();
                if (w != null)
                    w.close();
                if (r != null)
                    r.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

运行上述代码,得到如下结果,到D盘查看,发现存在test3.txt 文件 ,点击查看,文件内容也都开碑过来了,说明代码无误。

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

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

相关文章

自己创建的类,其他类中使用错误

说明:自己创建的类,在其他类中创建,报下面的错误(Cannot resolve sysmbol ‘Redishandler’); 解决:看下是不是漏掉了包名 加上包名,问题解决;

第9届Python编程挑战赛初中组初赛真题剖析-2023年全国青少年信息素养大赛

[导读]:超平老师计划推出《全国青少年信息素养大赛Python编程真题解析》50讲,这是超平老师解读Python编程挑战赛系列的第13讲。 全国青少年信息素养大赛(原全国青少年电子信息智能创新大赛)是“世界机器人大会青少年机器人设计与…

PyCharm安装pip依赖,如何添加国内镜像源?

目录 前言 PyCharm如何安装依赖 PyCharm如何配置国内镜像源 前言 首先我们都知道,使用pip安装依赖的方式,却很少有人知道使用PyCharm如何安装依赖。 PyCharm如何安装依赖 但你会发现,基本都是安装失败的,因为你是去外网下载的…

左神算法之中级提升班(8)

目录 【案例1】 【题目描述】 【思路解析】 【代码实现】 【案例2】 【题目描述】 【思路解析】 【代码实现】 【案例3】 【题目描述】 【思路解析】 【案例4】 【题目描述】 【思路解析】 【代码实现】 【案例5】 【题目描述】 【子序列概念】 【思路解析1 经典…

CTF-MISC:BUUCTF练习汇总(持续更新)

CTF-MISC:BUUCTF练习汇总 1、金三胖2、你竟然赶我走3、二维码4、大白 1、金三胖 解题思路: flag隐藏在gif图片帧中,使用在线GIF拆分工具即可 在线GIF图片帧拆分工具:https://uutool.cn/gif2img/ flag为:flag{he11oho…

应用层协议——https

文章目录 1. HTTPS 是什么2. 什么是"加密"3. 常见的加密方式4. 数据摘要 && 数字签名5. HTTPS 的工作过程探究5.1 方案1 - 只使用对称加密5.2 方案2 - 只使用非对称加密5.3 方案3 - 双方都使用非对称加密5.4 方案4 - 非对称加密 对称加密5.5 中间人攻击5.6 …

【MTI 6.S081 Lab】locks

【MTI 6.S081 Lab】locks Memory allocator (moderate)实验任务Hint解决方案 Buffer cache (hard)实验任务Hint解决方案数据结构设计初始化数据结构getrelse 本实验前去看《操作系统导论》第29章基于锁的并发数据结构,将会是很有帮助的。 在这个实验室中&#xff0…

懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒!

前言 系列首发gong zhong hao[『非同质前端札记』] ,若不想错过更多精彩内容,请“星标”一下,敬请关注gong zhong hao最新消息。 懒得改变原始对象?JavaScript代理模式教你怎样一步步偷懒! 何为代理模式 例如&#x…

倍增与ST算法

倍增与ST算法 倍增倍增原理倍增法的局限例题 :国旗计划 (洛谷 P4155)例题题解带注释的代码 ST算法ST算法原理ST算法步骤ST算法应用场合例题 :【模板】ST表 (洛谷 P3865) 倍增 倍增原理 倍增法的局限 例题 :国旗计划 (洛谷 P4155) 例题题解 带…

华为OD机试真题 Java 实现【报文回路】【2023 B卷 100分】,俗称“礼尚往来”

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、报文回路2、异常情况:3、解题思路 五、Java算法源码六、效果展示1、输入2、输出 华为OD机试 2023B卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA&…

《JavaSE-第二十章》之线程的创建与Thread类

文章目录 什么是进程?什么是线程?为什么需要线程? 基本的线程机制创建线程1.实现 Runnable 接口2.继承 Thread 类3.其他变形 Thread常见构造方法1. Thread()2. Thread(Runnable target)3. Thread(String name)4. Thread(Runnable target, Str…

epoll复用

cli #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <sys/socket.h>// 服务器ip #define IP "192.168.250.100" // 服务器端口 #define PORT 8888int main…

c++11 标准模板(STL)(std::basic_ifstream)(一)

定义于头文件 <fstream> template< class CharT, class Traits std::char_traits<CharT> > class basic_ifstream : public std::basic_istream<CharT, Traits> 类模板 basic_ifstream 实现文件流上的高层输入操作。它将 std::basic_istream…

Flink - souce算子

水善利万物而不争&#xff0c;处众人之所恶&#xff0c;故几于道&#x1f4a6; 目录 1. 从Java的集合中读取数据 2. 从本地文件中读取数据 3. 从HDFS中读取数据 4. 从Socket中读取数据 5. 从Kafka中读取数据 6. 自定义Source 官方文档 - Flink1.13 1. 从Java的集合中读取数据 …

二叉树(C语言)

文章目录 1.树1.1概念1.2相关定义1.3 表示&#xff08;左孩子右兄弟&#xff09; 2.二叉树2.1概念2.2特殊的二叉树1. 满二叉树&#xff1a;2. 完全二叉树&#xff1a; 2.3二叉树的性质2.4练习 3.二叉树的存储结构1. 顺序存储2. 链式存储 4.完全二叉树的代码实现4.1堆的介绍1.堆…

ssm德宏贸易项目java人资企业办公jsp源代码mysql

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 ssm德宏贸易项目 系统有1权限&#xff1a;管理员 二…

接口自动化测试平台

下载了大神的EasyTest项目demo修改了下<https://testerhome.com/topics/12648 原地址>。也有看另一位大神的HttpRunnerManager<https://github.com/HttpRunner/HttpRunnerManager 原地址>&#xff0c;由于水平有限&#xff0c;感觉有点复杂~~~ 【整整200集】超超超…

查询结果元数据-MetaData对象、数据库工具类的封装、通过反射实现数据查询的封装

六、查询结果元数据-MetaData对象 七、数据库工具类的封装 1、PropertieUtil类 2、DbUtil类 3、DBHepler类 查询&#xff1a; 4、TestDb测试类&#xff1a; 更新&#xff1a; 1&#xff09;插入&#xff1a; 2&#xff09;修改&#xff1a; 3&#xff09;删除&#xff1a; 查…

2024考研408-计算机网络 第二章-物理层学习笔记

文章目录 前言一、通信基础1.1、物理层基本概念1.1.1、认识物理层1.1.2、认识物理层的四种接口特性 1.2、数据通信基础知识1.2.1、典型的数据通信模型及相关术语1.2.2、数据通信相关术语1.2.3、设计数据通信系统要考虑的三个问题&#xff1a;问题1&#xff1a;采用单工通信/半双…

通讯录的实现(超详细)——C语言(进阶)

目录 一、创建联系人信息&#xff08;结构体&#xff09; 二、创建通讯录&#xff08;结构体&#xff09; 三、define定义常量 四、打印通讯录菜单 五、枚举菜单选项 六、初始化通讯录 七、实现通讯的的功能 7.1 增加加联系人 7.2 显示所有联系人的信息 ​7.3 单独查…