BufferedInputStream内用有一个很重要的private函数fill(),这个函数的原型如下:
[code="java"] private void fill() throws IOException {
byte[] buffer = getBufIfOpen();
if (markpos = buffer.length) /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
} else { /* grow buffer */
int nsz = pos * 2;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
}
众所周知,BufferedInputStream会缓存一部分数据(默认8K),这个函数的作用就是读取更多的数据到缓存,必要的时候会扩大缓存的内容。
讲解这个函数前,先了解一下BufferedInputStream中一些字段的含义:
如图所示,矩形的长度表示buf的长度,count表示buf中的可读数据长度,pos表示当前已读取到的位置,markpos表示上一次调用mark函数时pos的位置,如果没调用过mark函数,则为-1。marklength的含义是,在调用reset函数的时候,marklength范围内的缓存必须被保留,注意marklength不能大于marklimit(marklimit是缓存中容许保留的最大长度)。
下面开始解读这个函数:
getBufIfOpen是获取当前buf的引用;
if (markpos < 0)
pos = 0;
这句说明buf中没做过标记,没有数据需要保留,可以直接清空缓存buf;
else if (pos >= buffer.length)
这一句有两层含义:首先说明缓存中可能(注意,是可能)有数据需要保留,
同时说明缓存中已经没有可用的空间;
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
pos = sz;
markpos = 0;
}
这一段代码,是处理缓存中确实有数据要保留的情况,首先计算需要保留的数据
占用的空间int sz = pos - markpos;
然后将它们copy到缓存的头部System.arraycopy(buffer, markpos, buffer, 0, sz);
再将当前位置设置到(pos-markpos),markpos设置到缓存的起始位置;
else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
}
如果marklimit的值小于缓存的长度,说明buffer很大,从内存使用的角度考虑,此时
不宜再增大缓存的容量,在这种情形下直接丢弃buf中的已有内容;
else { /* grow buffer */
int nsz = pos * 2;
if (nsz > marklimit)
nsz = marklimit;
byte nbuf[] = new byte[nsz];
System.arraycopy(buffer, 0, nbuf, 0, pos);
if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
// Can't replace buf if there was an async close.
// Note: This would need to be changed if fill()
// is ever made accessible to multiple threads.
// But for now, the only way CAS can fail is via close.
// assert buf == null;
throw new IOException("Stream closed");
}
buffer = nbuf;
}
如果缓存的容量不是很大,则扩大一倍(int nsz = pos * 2),因为此时markpos为-1,
所以将0到pos的数据保留(System.arraycopy(buffer, 0, nbuf, 0, pos)),下面的if
语句是使用了原子变量引用更新,确保多线程环境下内存的可见性;
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
count = n + pos;
上面的代码是将缓存尽量的读满,并重新设置可读数据的长度count。
- 大小: 20.5 KB
分享到:
相关推荐
BufferedInputStream 的构造函数有两个: * `BufferedInputStream(InputStream in)`: 使用默认的缓冲大小(8192 字节)来创建一个 BufferedInputStream 对象。 * `BufferedInputStream(InputStream in, int size)`:...
BufferedInputStream源码分析图
BufferedInputStream 是缓冲输入流。它继承于FilterInputStream。 BufferedInputStream 的作用是为另一个输入流添加一些功能,例如,提供“缓冲功能”以及支持“mark()标记”和“reset()重置方法”。
当使用BufferedInputStream读取数据时,它实际上是从缓冲区中读取数据,而不是直接从底层数据源。缓冲区会预加载一定数量的数据(默认情况下是8192字节),只有当缓冲区数据读取完毕时,才会再次从底层数据源加载...
BufferedInputStream的用法1---马克-to-win java视频
BufferedInputStream的用法3---马克-to-win java视频缓存输字节流
java代码,使用字符流读取文件,让新手了解字符流,以及新手学习字符流。在学习过程中进步,用java中的BufferedOutputStream.
jdk api-BufferedInputStream基础、应用、实战
Java IO中的BufferedInputStream是Java I/O流处理中非常重要的一部分,它属于过滤输入流(FilterInputStream)的一个子类。BufferedInputStream的主要目的是提高输入流的读取效率,通过内部维护一个缓冲区来批量处理...
BufferedInputStream 的增强版,不使用 available()。 BuffereInputStream 的自定义实现,它根本不调用嵌套流的方法“available()”。 对于那些不阻止它或实现错误的 InputStreams 来说,这可能是合理和有帮助的 ...
1. 创建 BufferedInputStream 对象:使用 BufferedInputStream 的构造函数来创建一个新的 BufferedInputStream 对象。 2. 连接指定的资源:使用 HttpURLConnection 对象来连接指定的资源,并获取网络输入流。 3. ...
在Java I/O流处理中,`BufferedOutputStream` 和 `BufferedInputStream` 是两种非常重要的类,它们分别属于字节缓冲输出流和字节缓冲输入流。这两个类都是为了提高I/O操作的效率,通过在实际操作底层流之前,先将...
BufferedInputStream的用法2---马克-to-win java啊视频
在读取数据时,BufferedInputStream 会首先检查缓冲数组中是否有可用的数据,如果没有,那么它将调用 fill 方法来填充缓冲区。fill 方法的作用是从磁盘中读取数据并将其存入缓冲数组中。如果 fill 方法调用之后,pos...
在Java中,数学函数可以使用Math类中的方法。在本题中,正确的计算42度的余弦值的方法是`double d = Math.cos(Math.toRadians(42));`。 本文通过对给定文件的分析和解析,总结了Java程序设计、输入/输出流、表达式...
BufferedInputStream 的构造函数中,可以指定缓冲区的大小,以便根据需要调整缓冲区的大小。 DataInputStream 是另一个重要的子类,它可以用来装饰其它输入流,并且可以读取基本 Java 数据类型,如 int、long、...
**BufferedInputStream** 是Java中用于处理字节输入的缓冲流。它扩展了FilterInputStream,并添加了一个内部缓冲区,允许数据一次性读取多个字节,而不是每次只读一个字节。这在处理大文件或频繁读取的小文件时尤其...
15. 在GridBagLayout中,fill属性默认值是GridBagConstraints.NONE。 16. FilterInputStream类是InputStream的子类,它的子类包括DataInputStream、BufferedInputStream、PushbackInputStream等,因此不是这些子类...
例如,在Hadoop中,MapReduce任务中的Map函数可以读取来自HDFS的输入流,而Reduce函数则可以将结果写入到HDFS的输出流中。这种处理方式极大地简化了分布式数据处理的复杂性。 总的来说,Java流机制在Hadoop分布式...