哈喽,各位小伙伴们,你们好,我是喵手。
今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流学习,互相学习,一群人方能走的更远。
我是一名Java开发,所以日常接触到最多的就是java啦,所以我趁自己有空,就来好好回忆,把自己学到的会的,进行输出,不图什么有回报,只想能帮助到更多的小伙伴,就好。
小伙伴们在批阅的过程中,如果觉得文章不错,欢迎点赞、收藏、关注哦。三连即是对作者我写作道路上最好的鼓励与支持!
前言
在 Java 开发中,IO 操作是十分常见且重要的一个内容。在 IO 操作中,BufferedInputStream
类是一个十分重要的类,它可以提供缓冲和流的级联两个功能,使得读取操作变得更加高效,提供了一定的性能优化。本文将对 BufferedInputStream
类进行详细介绍。
摘要
本文将从 BufferedInputStream
类的定义入手,介绍其主要的功能、使用场景和优缺点,然后从源代码解析、应用场景案例和类代码方法介绍等方面深入探讨 BufferedInputStream
类的内部机制和使用方法,并提供测试用例对 BufferedInputStream
类进行实际测试。最后对全文内容进行总结,帮助读者更好地理解 BufferedInputStream
类。
BufferedInputStream
类
简介
BufferedInputStream
类继承自 FilterInputStream
类,它提供了缓冲和流的级联两个功能,可以提高读取操作的效率,减少 I/O 操作次数。若想了解更多可以继续往下看。
构造方法
BufferedInputStream 类定义了三个构造方法:
代码语言:java复制public BufferedInputStream(InputStream in);
public BufferedInputStream(InputStream in, int size);
public BufferedInputStream(InputStream in, byte[] buffer);
第一个构造方法创建一个未指定缓冲区大小的 BufferedInputStream 对象,第二个构造方法则创建一个指定缓冲区大小的 BufferedInputStream 对象,第三个构造方法则将指定的字节数组作为缓冲区。
源代码解析
BufferedInputStream 类底层最主要的实现是通过缓冲区来提升读取效率的,通过读取尽可能多的数据到缓冲区中,减少 I/O 操作次数。BufferedInputStream
的源代码实现中,最重要的两个方法就是 fill()
方法和 read() 方法。
fill()
方法用于将缓冲区中的数据填满,以便能够进行读取操作。read()
方法则是一个最重要的方法,它是 BufferedInputStream 类的read()
方法的实现,通过读取缓冲区中的数据,来达到提高读取效率的目的。在读取时,如果缓冲区中的数据已经全部被读取,那么就需要再次调用fill()
方法来填充缓冲区。这样就达到了高效读取的目的。
其源代码如下:
代码语言:java复制public class BufferedInputStream extends FilterInputStream {
protected volatile byte buf[];
protected int count;
protected int pos;
protected int markpos = -1;
protected int marklimit;
protected InputStream in;
private static int DEFAULT_BUFFER_SIZE = 8192;
private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
// 构造函数
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];
marklimit = size;
this.in = in;
}
// 读取数据到缓冲区
private void fill() throws IOException {
byte[] tmpbuf = buf;
if (markpos < 0)
pos = 0;
else if (pos >= tmpbuf.length)
if (markpos > 0)
pos = markpos;
else if (tmpbuf.length < marklimit)
tmpbuf = new byte[Math.min(marklimit, MAX_BUFFER_SIZE)];
else
if (markpos < 0)
pos = 0;
else
throw new IOException("Marked position invalid");
count = pos;
int n = in.read(tmpbuf, pos, tmpbuf.length - pos);
if (n > 0)
count = n pos;
}
// 从缓冲区读取数据
public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return (buf[pos ] & 0xff);
}
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;
// 如果没有数据可读取,就退出循环
InputStream input = in;
if (input != null && input.available() <= 0)
return n;
}
}
private synchronized 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;
}
}
上述源码个人见解如下:
BufferedInputStream
类继承自FilterInputStream
,并重写了其中的读取方法。buf
为缓冲区,count
表示缓冲区有效数据长度,pos
表示下一次从缓冲区读取的位置,markpos
表示标记的位置,marklimit
表示标记的上限。fill()
方法用于从输入流中读取数据到缓冲区。read()
方法从缓冲区中读取一个字节的数据。read(byte b[], int off, int len)
方法从缓冲区中读取len个字节的数据到b数组中的off位置。read1(byte[] b, int off, int len)
方法从缓冲区中读取len个字节的数据到b数组中的off位置。如果缓冲区中没有数据可供读取,就从输入流中读取数据到缓冲区。
总体来说,BufferedInputStream
类简单而且实用,能够提高输入流读取的效率,特别是在对文件进行读取时。
如下是部分源码截图展示:
如果同学们想了解更多与之相关的知识点,这就需要你们自己去摸索了,毕竟源码类都能在类中看到。
应用场景案例
在实际应用场景中,BufferedInputStream
类主要用于对大量数据的读取操作中。读取大量数据时,每次都直接从硬盘或网络中读取数据效率非常低,但是通过使用 BufferedInputStream
类进行缓存,可以大大提高读取速度,从而提升程序的整体性能。
以下代码展示了如何使用 BufferedInputStream 类读取文件:
代码语言:java复制package com.example.javase.io.fileProject;
import java.io.*;
/**
* @author 喵手
* @date 2023/10/20 14:59
*/
public class BufferedInputStreamTest {
//读取文件
public static void testReadFile_1() throws IOException {
FileInputStream fileInputStream = new FileInputStream(new File("testDoc.txt"));
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int data = bufferedInputStream.read();
while (data != -1) {
System.out.print((char) data);
data = bufferedInputStream.read();
}
bufferedInputStream.close();
}
public static void main(String[] args) throws IOException {
testReadFile_1();
}
}
根据如上案例执行演示结果如下:
优缺点分析
优点:
- 可以提高读取效率,减少 I/O 操作次数,从而提高程序的整体性能。
- BufferInputStream 类提供了缓冲和流的级联两个功能,使用起来方便简单。
缺点:
- 使用缓冲区可能会导致数据不及时更新。
- 缓冲区过大会占用过多内存,而缓冲区过小则不能充分发挥 BufferedInputStream 的优势。因此,需要根据实际情况设置合适的缓冲区大小。
类代码方法介绍
以下是 BufferedInputStream 类中最常用的几个方法:
public synchronized int read() throws IOException
:从输入流中读取下一个字节的数据。public synchronized int read(byte[] b, int off, int len) throws IOException
:从输入流中读取最多 len 个字节的数据到字节数组 b 中,从偏移量 off 开始存储。public synchronized int available() throws IOException
:返回在不受阻塞的情况下从输入流中能够读取的字节数。public synchronized void mark(int readlimit)
:将当前的流位置标记为 readlimit 参数的值。public synchronized void reset() throws IOException
:将流的位置重置到之前的标记位置。public boolean markSupported()
:判断该输入流是否支持 mark() 和 reset() 方法。
测试用例
以下是对 BufferedInputStream 类的测试用例:
代码语言:java复制 public static void testReadFile_2() throws IOException {
FileInputStream fileInputStream = new FileInputStream("testDoc.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 8);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = bufferedInputStream.read(buffer)) != -1) {
System.out.println(new String(buffer, 0, len));
}
bufferedInputStream.close();
}
public static void main(String[] args) throws IOException {
testReadFile_2();
}
根据如上测试用例,我们直接进行测试用例执行,演示结果如下:
测试代码分析:
如上测试代码定义了两个方法,一个是testReadFile_2(),一个是main()。其中,testReadFile_2()主要用于读取指定文件内容并输出到控制台,而main()方法则调用testReadFile_2()方法执行读取操作。
在testReadFile_2()方法中,首先通过FileInputStream类创建一个输入流对象fileInputStream,并将要读取的文件名"testDoc.txt"作为参数传入。接着,将fileInputStream对象传入BufferedInputStream类中作为参数,创建一个带有缓冲区的输入流对象bufferedInputStream。其中,缓冲区大小为8字节,即每次读取的数据量为8字节。
随后定义一个长度为1024的字节数组buffer,用于存储读取到的数据。进入循环后,调用bufferedInputStream对象的read()方法读取数据,并将读取到的数据存储在buffer数组中。如果读到文件结尾,则读取操作结束,退出循环。在循环体中,每次将buffer数组中读取到的数据转换成字符串并输出到控制台。
最后,调用bufferedInputStream对象的close()方法关闭输入流,释放资源。在main()方法中,直接调用testReadFile_2()方法执行读取操作。
全文小结
本文从 BufferedInputStream
类的定义出发,详细介绍了 BufferedInputStream
类的主要功能、使用场景和优缺点等内容,然后从源代码解析、应用场景案例、类代码方法介绍等方面深入剖析 BufferedInputStream
类的内部机制和使用方法,并提供测试用例对 BufferedInputStream
类进行实际测试。本文的目的是帮助 Java 开发者更好地了解 BufferedInputStream
类,提高其在实际开发中的应用能力。
总结
BufferedInputStream
类是 Java IO 类库中的一个重要类,它通过缓存机制可以提高读取操作的效率。在实际应用中,缓冲机制不仅可以加速数据的输入输出,还可以在数据的传输过程中减少 CPU 的占用,提高系统性能。但是在使用 BufferedInputStream
类的过程中,需要注意缓冲区大小的设置,避免过大或过小导致的性能问题。
... ...
文末
好啦,以上就是我这期的全部内容,如果有任何疑问,欢迎下方留言哦,咱们下期见。
... ...
学习不分先后,知识不分多少;事无巨细,当以虚心求教;三人行,必有我师焉!!!
wished for you successed !!!
⭐️若喜欢我,就请关注我叭。
⭐️若对您有用,就请点赞叭。
⭐️若有疑问,就请评论留言告诉我叭。
我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!