文章目录
-
- 1. 概念
- 2. 字段
-
- 1. BufferedInputStream
- 2. BufferedOutputStream
- 3. 方法
-
- 1. 构造器
-
- 1. BufferedInputStream
- 2. BufferedOutputStream
- 2. 其他方法
-
- 1. BufferedInputStream
- 2. BufferedOutputStream
- 4. 案例
- 5. 扩展
1. 概念
BufferedInputStream和BufferedOutputStream都是缓冲流,缓冲流实际上里面有一个缓冲区,即字节数组,用流读取存储在硬盘上较大文件的时,频繁从硬盘中读取数据效率比较低,花费时间较长.缓冲流的作用就是将数据先读取到内存里面,然后从内存里面读取数据,读取速度得到很大的提升
2. 字段
1. BufferedInputStream
- protected volatile byte buf[]:缓冲输入流中的缓冲区
- protected int count:缓冲输入流里面的有效字节数
- protected int pos:从缓冲区读取字节数据的当前位置
- protected int markpos = -1:缓冲区标记的位置,当调用mark()方法的时候,会将缓冲区当前位置pos保存到markpos
- protected int marklimit:mark()方法标记后再调用reset()方法之前最多读取的字节
- private static int DEFAULT_BUFFER_SIZE = 8192;
2. BufferedOutputStream
- protected byte buf[]:冲输出流中缓冲区
- protected int count:缓冲输出流中有效的字节数
3. 方法
1. 构造器
1. BufferedInputStream
- public BufferedInputStream(InputStream in) {this(in, DEFAULT_BUFFER_SIZE);}:创建的默认大小8192字节的字节数组
- public BufferedInputStream(InputStream in, int size):建的是指定size大小字节数组的缓冲输入流
2. BufferedOutputStream
- public BufferedOutputStream(OutputStream out) { this(out, 8192);}:创建默认大小为8192字节的缓冲输出流
- public BufferedOutputStream(OutputStream out, int size):创建指定大小size的缓冲输出流
2. 其他方法
1. BufferedInputStream
- public synchronized int read() throws IOException:从缓冲区读取一个字节
- public synchronized int read(byte b[], int off, int len) throws IOException:将缓冲区的数据读取到字节数组b的off位置开始,长度为len
- public synchronized long skip(long n) throws IOException:跳过字节的数
- public synchronized int available() throws IOException:从输入流中可读取字节总数的估算值
- public synchronized void mark(int readlimit):对缓冲区当前位置 pos 进行标记.并设置标记后可读取的最大值readlimit
- public synchronized void reset() throws IOException:将缓冲区的位置重置到 mark 标记的位置
- public boolean markSupported():是否支持标记
- public void close() throws IOException:关闭输入流
2. BufferedOutputStream
- public synchronized void write(int b) throws IOException:将数据b写到缓冲数组buf中
- public synchronized void write(byte b[], int off, int len) throws IOException:将字节数组b中off索引开始,长度为len个字节写到缓冲区中
- public synchronized void flush() throws IOException:刷新缓冲区,将缓冲区里面的数据写到输出流中
4. 案例
通过BufferedInputStream和BufferedOutputStream复制,效率极大提高
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
File source = new File("D:\\软件.zip");File dest = new File("D:\\copy\\soft.zip");copyFile(source, dest);}private static void copyFile(File source, File dest) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(source));BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest));byte buffer[] = new byte[1024];int len = 0;while ((len = bis.read(buffer)) != -1) {
bos.write(buffer);}bis.close();bos.close();}
}
5. 扩展
关于缓冲输入流填充方法fill().存在多种情况,分析如下:
- 缓冲区没有标记的情况下,即markpos<0时,缓冲区中已被读取过的字节不需要保存.即pos>=count时,会将pos和count重置为0.然后从输入流读取数据填充缓冲区0到buffer.length之间的位置
- 缓冲区标记的情况下.
- 即markpos>=0情况下当markpos>0的时,下次刷新缓冲的时候,需要将markpos到pos之间数据保留.从输入流中读取数据填充pos到buffer.length之间的位置.如下图,当markpos>0时,并且pos>=buffer.length.下次读取输入流的里面数据的时候,会将markpos到pos之间的数据保存.
- 当markpos=0的时候,buffer.length>marklimit,并且pos>buffer.length表示的是缓冲区里面没有剩余的位置.如果继续保留markpos到pos之间数据,那么刷新缓冲区之后,缓冲区依旧没有剩余位置,因为pos>=buffer.length.缓冲区没有空出位置,所以marklimit存在意义就是进行一个限定,根据buffer.length与marklimit大小来判断标记是否失效.源码中buffer.length>=marklimit的时候,标记失效.缓冲区里面0到buffer.length之间的位置是空的.可以进行填充
- 当markpos=0.buffer.length<marklimit,并且pos>buffer.length表示缓冲区没有剩余位置.则需要扩容;如下,扩充后容量的是2*pos和marklimit中的最小值.扩容后缓冲区会保留原先0-pos之间的数据.然后从输入流继续读取数据
- 即markpos>=0情况下当markpos>0的时,下次刷新缓冲的时候,需要将markpos到pos之间数据保留.从输入流中读取数据填充pos到buffer.length之间的位置.如下图,当markpos>0时,并且pos>=buffer.length.下次读取输入流的里面数据的时候,会将markpos到pos之间的数据保存.