面试官:Java中缓冲流真的性能很好吗?我看未必

news2024/12/28 4:55:32

一、写在开头

上一篇文章中,我们介绍了Java IO流中的4个基类:InputStream、OutputStream、Reader、Writer,那么这一篇中,我们将以四个基类所衍生出来,应对不同场景的数据流进行学习。
在这里插入图片描述

二、衍生数据流分类

我们上面说了java.io包中有40多个类,都从InputStream、OutputStream、Reader、Writer这4个类中衍生而来,我们以操作对象的维度进行如下的区分:

2.1 文件流

文件流也就是直接操作文件的流,可以细分为字节流(FileInputStream 和 FileOuputStream)和字符流(FileReader 和 FileWriter),我们在上面的已经说了很多了,这里就再赘述啦。

2.2 数组流

所谓数组流就是将内存中有限的数据进行读写操作的流,适应于数据量小,无需利用文件存储,提升程序效率。

我们以ByteArrayInputStream(字节数组输入流)为例:

public class TestService{
    public static void main(String[] args)  {
        try {
            ByteArrayInputStream bi = new ByteArrayInputStream("JavaBuild".getBytes());
            int content;
            while ((content = bi.read()) != -1) {
                System.out.print((char) content);
            }
            // 关闭输入流,释放资源
            bi.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

字节数组输出流(ByteArrayOutputStream)亦是如此,它们不需要创建临时文件,直接在内存中就可以完成对字节数组的压缩,加密,读写以及序列化。

2.3 管道流

管道(Pipe)作为一种在计算机内通讯的媒介,无论是在操作系统(Unix/Linux)层面还是JVM层面都至关重要,我们今天提到的通道流就是在JVM层面,同一个进程中不同线程之间数据交互的载体。

我们以PipedOutputStream和PipedInputStream为例,通过PipedOutputStream将一串字符写入到内存中,再通过PipedInputStream读取输出到控制台,整个过程并没有临时文件的事情,数据仅在两个线程之间流转。

public class TestService{
    public static void main(String[] args) throws IOException {
        // 创建一个 PipedOutputStream 对象和一个 PipedInputStream 对象
        final PipedOutputStream pipedOutputStream = new PipedOutputStream();
        final PipedInputStream pipedInputStream = new PipedInputStream(pipedOutputStream);

        // 创建一个线程,向 PipedOutputStream 中写入数据
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 将字符串 "沉默王二" 转换为字节数组,并写入到 PipedOutputStream 中
                    pipedOutputStream.write("My name is JavaBuild".getBytes());
                    // 关闭 PipedOutputStream,释放资源
                    pipedOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        // 创建一个线程,从 PipedInputStream 中读取数据并输出到控制台
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 定义一个字节数组用于存储读取到的数据
                    byte[] flush = new byte[1024];
                    // 定义一个变量用于存储每次读取到的字节数
                    int len = 0;
                    // 循环读取字节数组中的数据,并输出到控制台
                    while (-1 != (len = pipedInputStream.read(flush))) {
                        // 将读取到的字节转换为对应的字符串,并输出到控制台
                        System.out.println(new String(flush, 0, len));
                    }
                    // 关闭 PipedInputStream,释放资源
                    pipedInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
        // 启动线程1和线程2
        thread1.start();
        thread2.start();
    }
}

2.4 数据流

我们知道在Java中分为基本数据类型和引用类型,我们在做数据的读取与写入时,自然也会涉及到这种情况,比如我们将txt文件中的数字型数据以int类型读取到程序中,这时Java为我们提供了DataInputStream/DataOutputStream类。它们的常用方法为:

在这里插入图片描述

具体使用也相对比较简单:

DataInputStream dis = new DataInputStream(new FileInputStream("input.txt"));
// 创建一个 DataOutputStream 对象,用于将数据写入到文件中
DataOutputStream das = new DataOutputStream(new FileOutputStream("output.txt"));
// 读取四个字节,将其转换为 int 类型
int i = dis.readInt();
// 将一个 int 类型的数据写入到文件中
das.writeInt(1000);

2.5 缓冲流

对于数据的处理,CPU速度快于内存,内存又远快于硬盘,在大数据量情况下,频繁的通过IO向磁盘读写数据会带来严重的性能问题,为此Java中提供了一个缓冲流的概念,简单来说就是在内存中设置一个缓冲区,只有缓冲区中存储的数据到达一定量后才会触发一次IO,这样大大提升了程序的读写性能,常用的缓冲流有:BufferedInputStream、BufferedOutputStream、BufferedReader、BufferedWriter。
在这里插入图片描述

通过BufferedInputStream的底层源码我们可以看到,其内部维护了一个buf[]数据,默认大小为8192字节,我么也可以通过构造函数进行缓存大小设置。

public
class BufferedInputStream extends FilterInputStream {
    // 内部缓冲区数组
    protected volatile byte buf[];
    // 缓冲区的默认大小
    private static int DEFAULT_BUFFER_SIZE = 8192;
    // 使用默认的缓冲区大小
    public BufferedInputStream(InputStream in) {
        this(in, DEFAULT_BUFFER_SIZE);
    }
    // 自定义缓冲区大小
    public BufferedInputStream(InputStream in, int size) {
        super(in);
        if (size <= 0) {
            throw new IllegalArgumentException("Buffer size <= 0");
        }
        buf = new byte[size];
    }
}

至于说缓冲流到底能不能实现性能的提升,我们实践出真知,对于程序员来说所有的理论都不及上手写一写来得有效!这其实也涉及到一个经常被问的面试问题:java中的缓冲流真的性能很好吗?

刚好,我们手头有一本《Java性能权威指南》的PDF版,大小为66MB,我们通过普通的文件流和缓冲流进行文件的读取和复制,看一下耗时对比。

public class TestService{
    public static void main(String[] args) throws IOException {
        TestService testService = new TestService();
        testService.copyPdfWithPublic();
        testService.copyPdfWithBuffer();
    }
    /*通过普通文件流进行pdf文件的读取和拷贝*/
    public void copyPdfWithPublic(){
        // 记录开始时间
        long start = System.currentTimeMillis();
        try (FileInputStream fis = new FileInputStream("E:\\Java性能权威指南.pdf");
             FileOutputStream fos = new FileOutputStream("E:\\Java性能权威指南Public.pdf")) {
            int content;
            while ((content = fis.read()) != -1) {
                fos.write(content);
            }
            //使用数组充当缓存时,两者性能差距不大
            /*int len;
            byte[] bytes = new byte[4 * 1024];
            while ((len = fis.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
            }*/
            fis.close();
            fos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("使用普通文件流复制PDF文件总耗时:" + (end - start) + " 毫秒");
    }
    /*通过缓冲字节流进行pdf文件的读取和拷贝*/
    public void copyPdfWithBuffer(){
        // 记录开始时间
        long start = System.currentTimeMillis();
        try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Java性能权威指南.pdf"));
             BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\Java性能权威指南Buffer.pdf"))) {
            int content;
            while ((content = bis.read()) != -1) {
                bos.write(content);
            }
            /*int len;
            byte[] bytes = new byte[4 * 1024];
            while ((len = bis.read(bytes)) != -1) {
                bos.write(bytes, 0, len);
            }*/
            bis.close();
            bos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 记录结束时间
        long end = System.currentTimeMillis();
        System.out.println("使用缓冲字节流复制PDF文件总耗时:" + (end - start) + " 毫秒");
    }
}

输出:

使用普通文件流复制PDF文件总耗时:221611 毫秒
使用缓冲字节流复制PDF文件总耗时:228 毫秒

在这里插入图片描述
然后,我们将注释掉的代码放开,也就是我们采用一个缓存数组,先将数组存储起来后,两者之间的性能差距就没那么明显了。

使用普通文件流复制PDF文件总耗时:106 毫秒
使用缓冲字节流复制PDF文件总耗时:80 毫秒

在这种情况下,我们可以看到,甚至于普通的文件流的耗时是小于缓冲流的,所以对于这种情况来说,缓冲流未必一定性能最好。

2.6 打印流

对于System.out.println("Hello World");这句代码我想大家并不陌生吧,我们刚学习Java的第一堂课,老师们都会让我们输出一个Hello World,System.out 实际是用于获取一个 PrintStream 对象,print方法实际调用的是 PrintStream 对象的 write 方法。

public class PrintStream extends FilterOutputStream
    implements Appendable, Closeable {
}
public class PrintWriter extends Writer {
}

结尾彩蛋

如果本篇博客对您有一定的帮助,大家记得留言+点赞+收藏呀。原创不易,转载请联系Build哥!
在这里插入图片描述
如果您想与Build哥的关系更近一步,还可以关注“JavaBuild888”,在这里除了看到《Java成长计划》系列博文,还有提升工作效率的小笔记、读书心得、大厂面经、人生感悟等等,欢迎您的加入!
在这里插入图片描述

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

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

相关文章

python15 数据类型 集合类型

集合类型 无序的不重复元素序列 集合中只能存储不可变的数据类型 声明集合 使用 {} 定义 与列表&#xff0c;字典一样&#xff0c;都是可变数据类型 代码 集合类型 无序的不重复元素序列 集合中只能存储不可变的数据类型 声明集合 使用 大括号{} 定义 与列表&#xff0c;字典一…

【Python】理解『下采样』:原理与应用

是你多么温馨的目光 教我坚毅望着前路 叮嘱我跌倒不应放弃 没法解释怎可报尽亲恩 爱意宽大是无限 请准我说声真的爱你 &#x1f3b5; Beyond《真的爱你》 在数字信号处理、图像处理和机器学习中&#xff0c;下采样&#xff08;Downsampling&#xff09;是…

【Linux】 进程信号的发生

送给大家一句话&#xff1a; 何必向不值得的人证明什么&#xff0c;生活得更好&#xff0c;乃是为你自己。 -- 亦舒 进程信号的发生 1 何为信号2 信号概念的基础储备3 信号产生kill系统调用alarm系统调用异常core term Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢…

Blossom:支持私有部署的云端双链笔记软件分享

Blossom 是一款支持私有部署的云端双链笔记软件&#xff0c;能够帮助用户将笔记、图片和个人计划安排保存在自己的服务器中&#xff0c;并在任意设备之间实时同步。同时&#xff0c;它还可以作为一个动态博客使用。本文将详细介绍 Blossom 的特点和使用方法。 一、Blossom 的特…

CPN Tools学习——从平面网构建分层 PN

1.先创建平面petri网 创建如下petri网&#xff1a; CPN ide创建petri网真的舒服很多&#xff0c;但是教程又是CPN Tools的&#xff0c;我的想法是看两个版本能不能互通&#xff0c;在前者创建&#xff0c;在后者运行学习。 新增定义&#xff1a; colset E unit with e; 但…

探索Web Components

title: 探索Web Components date: 2024/6/16 updated: 2024/6/16 author: cmdragon excerpt: 这篇文章介绍了Web Components技术&#xff0c;它允许开发者创建可复用、封装良好的自定义HTML元素&#xff0c;并直接在浏览器中运行&#xff0c;无需依赖外部库。通过组合HTML模…

刷题记录(240613)

aliyun0512 1. 小红定义一个数组是好数组&#xff0c;当且仅当所有奇数出现了奇数次&#xff0c;所有偶数出现了偶数次。现在小红拿到了一个数组&#xff0c;她希望取一个该数组的非空子序列(可以不连续)&#xff0c;使得子序列是好数组。你能帮小红求出子序列的方案数吗?由于…

手机照片免费数据恢复软件EasyRecovery2024免费版下载

大家好&#xff01;今天我要给大家推荐一款非常棒的软件——EasyRecovery。相信大家都知道&#xff0c;电脑中的重要文件一旦丢失&#xff0c;对我们的工作和学习都会产生很大的影响。 而EasyRecovery软件就是专门解决这个问题的利器&#xff01;它能够帮助我们快速、有效地恢…

几种经典排序算法

几种经典排序算法 插入排序折半插入排序法 选择排序冒泡排序希尔排序堆排序二路归并排序快速排序 在介绍排序之前&#xff0c;先来说说&#xff0c;研究不同的排序主要是要研究他们的哪些不同&#xff1a; 时间性能。即排序过程中元素之间的比较次数与元素移动次数。我们此次讨…

【JavaEE进阶】——利用框架完成功能全面的图书管理系统

目录 &#x1f6a9;项目所需要的技术栈 &#x1f6a9;项目准备工作 &#x1f388;环境准备 &#x1f388;数据库准备 &#x1f6a9;前后端交互分析 &#x1f388;登录 &#x1f4dd;前后端交互 &#x1f4dd;实现服务器代码 &#x1f4dd;测试前后端代码是否正确 &am…

Caffe、PyTorch、Scikit-learn、Spark MLlib 和 TensorFlowOnSpark 概述

在 AI 框架方面,有几种工具可用于图像分类、视觉和语音等任务。有些很受欢迎,如 PyTorch 和 Caffe,而另一些则更受限制。以下是四种流行的 AI 工具的亮点。 Caffee Caffee是贾扬青在加州大学伯克利分校(UC Berkeley)时开发的深度学习框架。该工具可用于图像分类、语音和…

Nativefier—使用—快速将网站打包成桌面程序

--天蝎座 Nativefier简介 Nativefier是一个命令行工具&#xff0c;仅仅通过一行代码就可以轻松地为任何的网站创建桌面应用程序&#xff0c;应用程序通过Electron打包成系统可执行文件&#xff08;如.app, .exe等&#xff09;&#xff0c;可以运行在Windows&#xff0c;Mac和L…

需求:如何给文件添加水印

今天给大家介绍一个简单易用的水印添加框架&#xff0c;框架抽象了各个文件类型的对于水印添加的方法。仅使用几行代码即可为不同类型的文件添加相同样式的水印。 如果你有给PDF、图片添加水印的需求&#xff0c;EasyWatermark是一个很好的选择&#xff0c;主要功能就是传入一…

Mybatis工作流程和插件开发

在了解插件开发之前&#xff0c;我们先总体的来梳理一下Mybatis的大致执行流程&#xff1a; 1.new SqlSessionFactoryBuilder().build(inputStream):先根据配置文件&#xff08;包含了全局配置文件和映射配置文件&#xff09;初始化一个对象Configuration&#xff08;这里对象里…

LaTex入门教程

目录 1.说明 2.页面的分区 3.入门介绍 &#xff08;1&#xff09;命令 &#xff08;2&#xff09;环境 &#xff08;3&#xff09;声明 &#xff08;4&#xff09;注释 4.代码结构 &#xff08;1&#xff09;导言区 &#xff08;2&#xff09;支持中文 &#xff08;3…

2024都市解压爆笑喜剧《脑洞大开》6月28日上映

随着暑期档的临近&#xff0c;电影市场迎来了一剂强心针——由何欢、王迅、克拉拉、卜钰、孙越、九孔等众多实力派笑星联袂主演的都市解压爆笑喜剧《脑洞大开》正式宣布定档&#xff0c;将于6月28日在全国各大影院欢乐上映&#xff0c;誓为观众带来今夏最畅快淋漓的笑声风暴。 …

逆天改命 17岁中专女生横扫全球数学竞赛

“逆天改命!17岁中专女生横扫全球数学竞赛,清华北大高手纷纷落马!” 最近全网被这则消息震惊了。 来!随便挑几个题目,让大家体验一下阿里巴巴全球数学竞赛的难度? 数学是人工智能算法的基石。它为算法提供了逻辑框架和分析工具,使得人工智能能够处理复杂的数据和问…

驾考模拟 | 电脑上使用浏览器模拟科目一考试

驾考模拟 背景 有个亲戚要考科目一&#xff0c;大叔之前没怎么用过电脑&#xff0c;想要在电脑上练习科目一&#xff0c;找找使用电脑考试的感觉。 有一些本地安装的软件可以满足这个需求&#xff0c;但通常要付费&#xff0c;没这个必要&#xff0c;毕竟只是用来模拟考的。 …

【最新鸿蒙应用开发】——鸿蒙中的“Slot插槽”?@BuilderParam

构建函数-BuilderParam 传递 UI 1. 引言 BuilderParam 该装饰器用于声明任意UI描述的一个元素&#xff0c;类似slot占位符。 简而言之&#xff1a;就是自定义组件允许外部传递 UI Entry Component struct Index {build() {Column({ space: 15 }) {SonCom() {// 直接传递进来…

《大数据分析》期末考试整理

一、单项选择题&#xff08;1*9&#xff09; 1.大数据发展历程&#xff1a;出现阶段、热门阶段和应用阶段 P2 2.大数据影响 P3 1&#xff09;大数据对科学活动的影响 2&#xff09;大数据对思维方式的影响 3&#xff09;大数据对社会发展的影响 4&#xff09;大数…