BufferedInputStream解读

  咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java之IO流啦,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好习惯,别被干货淹没了哦~

在这里插入图片描述

前言

  在进行Java编程时,避免不了要进行一些文件操作。虽然Java提供了很多类和方法来进行文件操作,但是由于I/O操作是比较费时的,所以我们需要考虑如何优化文件操作的效率。本文介绍了如何使用Java中的BufferedInputStream类来提高I/O操作的效率。

摘要

  本文主要介绍了如何使用Java中的BufferedInputStream类来优化I/O操作。首先介绍了BufferedInputStream类的作用和原理,然后分别从文件读取和文件写入两个角度,介绍了如何使用BufferedInputStream类来提高文件操作的效率。最后通过测试用例来验证了BufferedInputStream类的优化效果。

BufferedInputStream

简介

  BufferedInputStream是Java中的一个输入流,它实现了输入流的缓冲功能,使读取数据更加高效。当从一个InputStream中读取数据时,Java在内部会一次读取一个字节。这种方式读取数据的效率非常低,因为每次读取都需要和硬盘或网络进行IO操作,而这些操作非常耗时。因此,使用BufferedInputStream可以先将读取的数据缓存到内存中,在内存中慢慢读取,这样就可以减少IO操作的次数,提高读取数据的效率。在使用BufferedInputStream时,可以通过调用read()方法来读取数据,该方法会从缓冲区中读取数据,如果缓冲区中没有数据,则会调用底层流来读取数据。

作用和原理

  BufferedInputStream类是Java中的一个输入流缓冲器,它可以提高I/O操作的效率。BufferedInputStream类的原理是,当我们从文件中读取数据时,它会先将数据读入内存缓冲区中,然后再从缓冲区中逐个地读取数据。这样可以减少一些不必要的I/O操作,从而提高读取数据的效率。

优缺点

  BufferedInputStream是Java中的一个输入流包装类,它提供了输入流缓冲区的功能,可以提高读取数据的效率。

优点:

  1. 提供了输入流的缓冲功能,减少了底层输入流的读取次数。这种减少I/O操作的方式可以显著提高读取数据的性能,特别是在处理大量数据时。
  2. 具有预读的功能,可以一次性读取多个字节到缓冲区中,从而减少了对底层输入流的访问次数。
  3. 可以通过设置合适的缓冲区大小来优化读取性能,尤其是在连续读取大型数据块时。

缺点:

  1. 需要额外的内存空间来存储缓冲区,可能会占用较大的内存。
  2. 当读取数据量较小时,缓冲区的额外开销可能会引起性能下降。

应用场景

  1. 读取大文件或数据流时,使用BufferedInputStream可以提高读取性能。
  2. 在网络传输中,可以使用BufferedInputStream来缓冲输入流,减少网络I/O的次数,提高网络传输性能。
  3. 当需要连续读取大量数据块时,可以使用BufferedInputStream来将其存储在缓冲区中,减少对底层输入流的访问次数。

源码分析

  在BufferedInputStream的源码中,它维护了一个内部的字节数组缓冲区,默认缓冲区大小为8192字节(8KB)。当从BufferedInputStream中读取数据时,它会先检查缓冲区中是否还有可读取的数据,如果有,则直接从缓冲区中返回数据;如果没有,则从底层输入流中读取数据,并同时将读取的数据存入缓冲区中。在写入数据时也是类似的过程,先写入缓冲区,当缓冲区满或者需要刷新缓冲时,再将数据写入底层输出流。

  BufferedInputStream的源码比较复杂,涉及缓冲区的管理、数据读写等操作,通过内部的缓冲区来实现数据的快速读取和写入。在具体使用时,我们只需要关注使用API即可,无需深入理解其具体实现细节。

  由于BufferedInputStream主要的作用是在数据源和程序之间添加一个缓冲区,来提高IO操作的效率。读取数据时,BufferedInputStream先从缓冲区中读取,如果缓冲区中没有数据,则从数据源中读取一定量的数据放入缓冲区中,然后再从缓冲区中读取数据,这样就可以避免频繁地访问物理设备,提高了效率。

下面是BufferedInputStream的源码分析:

public class BufferedInputStream extends FilterInputStream {protected volatile byte buf[];//缓冲区大小protected int count;protected int pos;protected int markpos = -1;protected int marklimit;protected boolean mSkipLF = false;//默认缓冲区大小static int defaultBufferSize = 8192;//跳过缓冲区数据并重新读取数据private void fill() throws IOException {//pos记录缓存区的位置pos = 0;count = 0;int n = in.read(buf, pos, buf.length);if (n > 0) {//如果成功从输入流中读取数据count = n;}}//构造方法传入InputStream流对象public BufferedInputStream(InputStream in) {this(in, defaultBufferSize);}public BufferedInputStream(InputStream in, int size) {super(in);if (size <= 0) {throw new IllegalArgumentException("Buffer size <= 0");}buf = new byte[size];}//读取单个字节public synchronized int read() throws IOException {//如果当前数据已经读取完了,从输入流读取数据并缓存if (pos >= count) fill();//如果读完了还为空则返回-1return (pos < count) ? (buf[pos++] & 0xff) : -1;}//读取多个字节private int read1(byte[] b, int off, int len) throws IOException {int avail = count - pos;//如果缓存区正在被使用,则重新从流中读取数据到缓冲区中if (avail <= 0) {if (len >= buf.length && markpos < 0) {return in.read(b, off, len);}fill();avail = count - pos;if (avail <= 0) return -1;}int cnt = (avail < len) ? avail : len;System.arraycopy(buf, pos, b, off, cnt);pos += cnt;return cnt;}//读取多个字节,并返回读取的字节数public synchronized int read(byte b[], int off, int len)throws IOException {//校验参数范围if (b == null) {throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int n = 0;//连续读取for (;;) {int nread = read1(b, off + n, len - n);if (nread <= 0) return (n == 0) ? nread : n;n += nread;//读够了就退出循环if (n >= len) return n;}}//跳过指定字节数public synchronized long skip(long n) throws IOException {if (n <= 0) {return 0;}//现将缓存区的数据跳过long avail = count - pos;if (avail <= 0) {//如果缓存区没有数据,则直接跳过n个字节return in.skip(n);}long skipped = (avail < n) ? avail : n;pos += skipped;n -= skipped;//如果还需要跳过的字节数超过了缓存区大小,则直接调用输入流的skip方法跳过if (n > 0) {skipped += in.skip(n);}return skipped;}//返回当前可读取的字节数public synchronized int available() throws IOException {int n = count - pos;int avail = in.available();return (n > (Integer.MAX_VALUE - avail)) ? Integer.MAX_VALUE : n + avail;}//标记当前位置public synchronized void mark(int readlimit) {marklimit = readlimit;markpos = pos;}//重置到上一次标记的位置public synchronized void reset() throws IOException {if (markpos < 0) {throw new IOException("Resetting to invalid mark");}pos = markpos;}//判断是否支持mark和reset方法public boolean markSupported() {return true;}//关闭流public void close() throws IOException {byte[] buffer;synchronized (this) {buffer = buf;buf = null;}if (buffer != null) {//调用输入流的close方法关闭流in.close();}}
}

  从源码中可以看出,BufferedInputStream主要是通过缓冲区来提高了读取效率,其读取过程与InputStream的读取过程基本一致,只不过在数据从输入流中读取后,会先将其缓存到一个缓冲区中,然后再从缓冲区中读取数据。同时,BufferedInputStream还提供了markreset方法,可以对数据流进行标记和重置,方便对流的操作。

使用BufferedInputStream类读取文件

  在进行文件读取时,我们可以使用BufferedInputStream类来提高读取效率。下面是一个使用BufferedInputStream类读取文件的示例代码:

try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./template/hello.txt"))) {byte[] buffer = new byte[1024];int length;while ((length = bis.read(buffer)) != -1) {// do something with the data}
} catch (IOException e) {// handle exception
}

  上面的代码中,我们首先创建了一个BufferedInputStream对象,并将其包装在一个try-with-resources语句中,这样可以自动关闭资源。然后我们创建一个字节数组作为缓冲区,读取文件时每次读取1024个字节,读取到文件末尾时返回-1。我们可以在while循环中对读取到的数据进行处理。

  使用BufferedInputStream类读取文件时,每次读取的数据会先被读入缓冲区中,当缓冲区的数据被读取完后,再从文件中读取新的数据。这样可以减少I/O操作的次数,提高读取数据的效率。

使用BufferedInputStream类写入文件

  在进行文件写入时,我们同样可以使用BufferedInputStream类来提高写入效率。下面是一个使用BufferedInputStream类写入文件的示例代码:

try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("./template/hello.txt"))) {byte[] data = "Hello, jym! ".getBytes();bos.write(data);
} catch (IOException e) {// handle exception
}

  上面的代码中,我们首先创建了一个BufferedOutputStream对象,并将其包装在一个try-with-resources语句中,这样可以自动关闭资源。然后我们将要写入的数据转换成字节数组,并通过BufferedOutputStream对象将数据写入到文件中。

  使用BufferedInputStream类写入文件时,每次写入的数据会先被写入到缓冲区中,当缓冲区的数据写满后,再将缓冲区中的数据一次性写入到文件中。这样可以减少I/O操作的次数,提高写入数据的效率。

测试用例

代码演示

  为了验证BufferedInputStream类的优化效果,我们可以编写一个测试用例。下面是一个使用BufferedInputStream类读取文件的测试用例:

package com.example.javase.io.bufferedInputStream;import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;/*** @author bug菌* @version 1.0* @date 2023/10/13 17:51*/
public class BufferedInputStreamTest {public static void main(String[] args) {long start = System.currentTimeMillis();try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream("./template/hello.txt"))) {byte[] buffer = new byte[1024];int length;while ((length = bis.read(buffer)) != -1) {String content = new String(buffer, 0, length);System.out.println("读取内容为:" + content);}} catch (IOException e) {// handle exception}long end = System.currentTimeMillis();System.out.println("Time used: " + (end - start) + "ms");}
}

  上面的代码中,我们首先记录了开始时间,然后使用BufferedInputStream类读取文件,并在while循环中对读取到的数据进行处理。最后,在读取数据时,将字节数组转换为字符串,并使用 System.out.println() 方法打印出来;并记录了结束时间,并输出总共使用的时间。

  我们可以在不使用BufferedInputStream类的情况下编写一个相同的测试用例,然后比较两个测试用例的运行时间,从而验证BufferedInputStream类的优化效果。

测试代码解析

这段代码演示了如何使用BufferedInputStream读取文件内容。

  1. 首先导入需要的类,包括BufferedInputStreamFileInputStreamIOException等;

  2. 在main函数中,首先记录程序开始的时间;

  3. 使用try-with-resources语句创建一个BufferedInputStream对象,它包装了一个FileInputStream对象,用于读取指定路径下的hello.txt文件;

  4. 创建一个byte数组作为缓冲区,长度为1024;

  5. 使用while循环读取文件内容,每次读取的数据被存储在缓冲区中,长度由read()方法返回;

  6. 将从缓冲区中读取的字节转换为字符串,输出到控制台;

  7. catch IOException异常,处理异常;

  8. 记录程序结束的时间;

  9. 输出程序执行时间。

  需要注意的是,使用BufferedInputStream可以提高读取文件的效率,但在读取大文件时,可能会导致内存溢出,需要注意调整缓冲区的大小。

测试结果

如下是运行测试用例所得截图,仅供参考:

在这里插入图片描述

小结

  通过本文的介绍,我们了解了如何使用Java中的BufferedInputStream类来提高I/O操作的效率。我们可以使用BufferedInputStream类来读取文件和写入文件,达到减少I/O操作次数、提高效率的目的。同时我们还编写了一个测试用例来验证BufferedInputStream类的优化效果。

总结

  BufferedInputStream类是Java中的一个输入流缓冲器,它可以提高I/O操作的效率。我们可以使用BufferedInputStream类来读取文件和写入文件,达到减少I/O操作次数、提高效率的目的。通过编写测试用例,我们验证了BufferedInputStream类的优化效果。在进行文件操作时,我们可以尽可能使用BufferedInputStream类来提高效率。

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

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

相关文章

继承和多态(2)(多态部分)

提前讲的重要知识点 一个类在没有父类的情况下默认有一个父类为Object类。 而当在有父类情况下&#xff0c;如果你那父类没有父类&#xff0c;则其父类的父类默认为object类&#xff0c;所以即使一个类有父类&#xff0c;其内部还是有object类。 object类都是隐藏起来的&…

【周总结】

周总结 完成项目混合版时区改造 完成相关jira问题的修改 完成老版本APP数据保存接口的兼容&#xff0c;手动赋值时区 2024/03/24 天气阴 一点不冷 1.Its time to go、Spring is coming&#xff01; 2. Its a nice day that staying with friends in a peaceful …

2024年云服务器ECS价格表出炉——腾讯云

腾讯云服务器多少钱一年&#xff1f;61元一年起。2024年最新腾讯云服务器优惠价格表&#xff0c;腾讯云轻量2核2G3M服务器61元一年、2核2G4M服务器99元一年可买三年、2核4G5M服务器165元一年、3年756元、轻量4核8M12M服务器646元15个月、4核16G10M配置32元1个月、312元一年、8核…

成功案例|全基因组测序+GWAS联合分析揭示不同种族帕金森病的遗传同质性和异质性

发表期刊&#xff1a;npj Parkinson’s Disease 影响因子&#xff1a;8.7 测序方式&#xff1a;WGS 研究对象&#xff1a;人 1 研究背景 帕金森病&#xff08;PD&#xff09;是一种常见的与年龄相关的神经退行性疾病&#xff0c;其特征是运动迟缓、姿势不稳定、僵硬和静息…

Redis中的过期键删除策略

过期键删除策略 概述 数据库键的过期时间都保存在过期字典中&#xff0c;并且知道根据过期时间去判断一个键是否过期,剩下的问题是&#xff1a;如果一个键过期了&#xff0c;那么它什么时候会被删除呢? 这个问题有三种可能的答案&#xff0c;它们分别代表了三种不同的删除策…

【linux】进程的地址空间

1.代码看现象引入 #include<stdio.h>#include<unistd.h>#include<string.h> #include<stdlib.h>int val100;int main (){ printf("i am father,pid:%d,ppid:%d,val:%d&#xff0c;&val:%p\n",getpid(),getppid(),val,&val);size_t…

vue2 和 vue3 配置路由有什么区别

vue2 和 vue3 配置路由有什么区别 初始化路由器实例&#xff1a;注入到应用中&#xff1a;动态路由参数和捕获所有路由&#xff1a;编程式导航 API&#xff1a;异步加载组件&#xff1a; vue2 如何 使用路由 第一步&#xff1a;安装 vue-router第二步&#xff1a;创建路由组件第…

【k8s】kubeasz 3.6.3 + virtualbox 搭建本地虚拟机openeuler 22.03 三节点集群 离线方案

kubeasz项目源码地址 GitHub - easzlab/kubeasz: 使用Ansible脚本安装K8S集群&#xff0c;介绍组件交互原理&#xff0c;方便直接&#xff0c;不受国内网络环境影响 拉取代码&#xff0c;并切换到最近发布的分支 git clone https://github.com/easzlab/kubeasz cd kubeasz gi…

<Linux> 模拟实现文件流 - 简易版

目录 1. FILE 结构设计 2、函数使用及分析 3、文件打开 fopen 4. 缓冲区刷新fflush 5. 数据写入fwrite 6. 文件关闭 fclose 7. 测试 8. 小结 1. FILE 结构设计 在设计 FILE 结构体前&#xff0c;首先要清楚 FILE 中有自己的缓冲区及冲刷方式 缓冲区的大小和刷新方式因…

JVM监控工具

JVM监控工具 文章目录 JVM监控工具jpsjmapjmap -histo 进程idjmap -heap 进程id (查看堆信息)jmap -dump:formatb,filefilename.hprof 进程id (将堆当前时刻快照信息dump到文件中) JSTACKjstack 查看死锁信息jstack找出占用cpu最高的线程堆栈信息 jinfo查看jvm参数查看java系统…

Perfetto Trace抓取

1. Perfetto简介 Perfetto 是一个用于 Android 系统的性能跟踪工具&#xff0c;可以帮助开发者分析系统性能和调试问题。 Perfetto 是 Android 10 中引入的全新平台级跟踪工具。这是适用于 Android、Linux 和 Chrome 的更加通用和复杂的开源跟踪项目。 在低于Android R的版本上…

量子计算新“尺度”:用经典计算机评估复杂量子系统!

未来的量子计算机有望在计算机科学、医疗、商业、化学、物理学等多个领域解决难题&#xff0c;从而超越传统计算机。然而&#xff0c;目前的量子计算机仍存在局限&#xff0c;主要是由于它们固有的错误率。为此&#xff0c;研究者正致力于降低这些错误率。 一种研究量子计算机误…

Linux系统部署Paperless-Ngx文档管理系统结合内网穿透实现公网访问

文章目录 1. 部署Paperless-ngx2. 本地访问Paperless-ngx3. Linux安装Cpolar4. 配置公网地址5. 远程访问6. 固定Cpolar公网地址7. 固定地址访问 Paperless-ngx是一个开源的文档管理系统&#xff0c;可以将物理文档转换成可搜索的在线档案&#xff0c;从而减少纸张的使用。它内置…

机械硬盘与固态硬盘究竟该适合选用哪种,看完本文你就了解了!

随着科技的发展,计算机存储技术经历了从传统的机械硬盘(HDD)到现代固态硬盘(SSD)的革新变迁。在这篇文章中,我们将深入探讨机械硬盘与固态硬盘在功能特点上的显著区别,帮助用户更好地理解这两种存储设备的核心优势与不足。 一、存储原理与结构差异 1. 机械硬盘(HDD) …

Midjourney AI绘图工具介绍及使用

介绍 Midjourney是一款目前被誉为最强的AI绘图工具。只要输入想到的文字&#xff0c;就能通过人工智能产出相对应的图片。 官网只是宣传和登录入口&#xff0c;提供个人主页、订阅管理等功能&#xff0c;Midjourney实际的绘画功能&#xff0c;是在另外一个叫discord的产品中实…

网络电视盒子哪个品牌好?2024畅销电视盒子排行榜

电视盒子的品牌和产品非常多&#xff0c;让新手在选购时难度增大&#xff0c;大部分消费者在此时会选择参考销量排名情况&#xff0c;小编这次结合各个电商平台的销量和用户评价整理了电视盒子排行榜&#xff0c;想买电视盒子不知道网络电视盒子哪个品牌好可以收藏。 TOP 1.泰捷…

论文导读 | 漫谈图神经网络

本文主要介绍图神经网络相关内容&#xff0c;包括图神经网络的基本结构以及近期研究进展。 背景 在实际生活中&#xff0c;许多数据都可以用图的形式表达&#xff0c;比如社交网络、分子模型、知识图谱、计算机网络等。图深度学习旨在&#xff0c;显式利用这些数据中的拓扑结…

3.18_C++_day6_作业

作业要求&#xff1a; 程序代码&#xff1a; #include <iostream>using namespace std;class Animal { private:string name;string color;int *age; public://无参构造函数Animal(){cout << "Animal::无参构造函数" << endl;}//有参构造函数Anim…

[Linux初阶]which-find-grep-wc-管道符命令

目录 一.which 二.find a.-name b.-size 三.grep 四.wc 五.管道符(|) 五.总结 一.which 语法格式: which [命令] Linux中的一个个命令,本体上就是一个个的二进制可执行程序(相当于windows中的.exe文件). 在Linux中,一切皆文件. which命令:用于查看指定命令的可执行…

【JS进阶】第3天

JavaScript 进阶 - 第3天笔记 理论较多&#xff0c;主要讲解原型对象和对象原型 了解构造函数原型对象的语法特征&#xff0c;掌握 JavaScript 中面向对象编程的实现方式&#xff0c;基于面向对象编程思想实现 DOM 操作的封装。 了解面向对象编程的一般特征掌握基于构造函数原…