javaIO流之缓冲流源码浅析及使用方法
一.缓冲流概述及适用场景
java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装。
当对文件或其他目标频繁读写或操作效率低,效能差。这时使用缓冲流能够更高效的读写信息。因为缓冲流先将数据缓存起来,然后一起写入或读取出来。
缓存的好处还在于不用频繁的进行IO操作,大部分时候这些操作其实是对缓存变量buffer进行的操作。
二.缓冲流的分类
对应四种IO流基类,分别是:
字节输入缓冲流:BufferedInputStream
字节输出缓冲流:BufferedOutputStream
字符输入缓冲流:BufferedReader
字符输出缓冲流:BufferedWriter
三.原理
BufferedInputStream 内部有一个缓冲区,默认大小为8M,每次调用read方法的时候,它首先尝试从缓冲区里读取数据,若读取失败(缓冲区无可读数据),则选择从物理数据源 (譬如文件)读取新数据(这里会尝试尽可能读取多的字节)放入到缓冲区中,最后再将缓冲区中的内容返回给用户。由于从缓冲区里读取数据远比直接从存储介质读取速度快,所以BufferedInputStream的效率很高。
那BufferedOutputStream就是先把数据写到缓冲区里,等到缓冲区满了再一次性写到磁盘。这样就减少了与硬件IO的操作,省时不少。
带缓冲的字符流原理同理。
三.源码浅析及使用方法
1.BufferedInputStream
1). 继承关系:
public class BufferedInputStream extends FIlterInputStream
2).成员变量:
protected volatile byte[] buf
存储数据的内部缓冲区数组。
protected int count
指当前缓冲区的有效字节数,而不是输入流中的有效字节数。
protected int marklimit
标记的最大值。
protected int markpos
当前缓冲区的标记位置。
markpos和reset()配合使用才有意义。
操作步骤:
(01) .通过mark() 函数,保存pos的值到markpos中。
(02) .通过reset() 函数,会将pos的值重置为markpos。
接着通过read()读取数据时,就会从mark()保存的位置开始读取。
protected int pos
当前缓冲区的位置索引,而不是输入流中的位置索引。
3).构造函数:
新建一个缓冲区大小为8192的BufferedInputStream
public BufferedInputStream(InputStream in)
新建指定缓冲区大小的BufferedInputStream
public BufferedInputStream(InputStream in, int size)
4).常用方法:
int available()//下一个字节是否存可读,返回从该输入流中可以读取(或跳过)
//的字节数的估计值,而不会被下一次调用此输入流的方法阻塞。
void close() //关闭此输入流并释放与流相关联的任何系统资源。
void mark(int readlimit)//设置标记位置
boolean markSupported() //测试这个输入流是否支持 mark和 reset方法。
int read() //读取下一个字节
int read(byte[] b, int off, int len)
//从给定的偏移off开始,将字节输入流中的字节读入指定的字节数组。
void reset()
//从最近的mark操作之后读取的所有字节在从包含的输入流中取出新的字节之前重新 读取。
long skip(long n) //跳过字符
5).使用方法代码展示:
import java.io.*;
public class BufferedInputStreamDemo {
public static void main(String[] args) {
try {
//创建字节输入节点流实例
FileInputStream fileInputStream = new FileInputStream("D:\\test.txt");
//通过节点流来创建缓冲流实例
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
//将字节缓冲流转换为字符输入流,方便读取操作
InputStreamReader inputStreamReader = new InputStreamReader(bufferedInputStream);
//存取读取的数据
char[] chars = new char[512];
//标记数据读取结束
int len ;
StringBuffer stringBuffer = new StringBuffer();
while ((len = inputStreamReader.read(chars)) != -1) {
stringBuffer.append(new String(chars, 0, len));//字符串拼接
}
//读取数据完成后关闭流实例
inputStreamReader.close();
bufferedInputStream.close();
fileInputStream.close();
//输出检验读取的数据
System.out.println(stringBuffer);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试结果:
2.BufferedOutputStream
1). 继承关系:
public class BufferedOutputStream extends FIlterOutputStream
2). 成员变量:
protected byte[] buf
存储数据的内部缓冲区。
protected int count
缓冲区中有效字节的数量。
3). 构造函数:
BufferedOutputStream(OutputStream out)
//创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
BufferedOutputStream(OutputStream out, int size)
//创建一个新的缓冲输出流,以便以指定的缓冲区大小将数据写入指定的底层输出流。
4). 常用方法:
void flush() //刷新缓冲输出流。
void write(byte[] b, int off, int len)
//从指定的字节数组写入 len个字节,从偏移 off开始到缓冲的输出流。
void write(int b) //将指定的字节写入缓冲的输出流。
5). 使用方法代码展示:
import java.io.BufferedOutputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class BufferedOutputStreamDemo {
public static void main(String[] args) {
try {
//创建一个字节输出流实例
FileOutputStream fileOutputStream = new FileOutputStream("D:\\test.txt");
//根据字节输出流对象构造一个字节缓冲流
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
String s = "字节输出缓冲流测试!";
bufferedOutputStream.write(s.getBytes());
//一定记得刷新,刷新到内核空间的缓冲区
bufferedOutputStream.flush();//关闭缓冲流时,也会刷新一次缓冲区
//输出完成后,关闭流实例
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试结果:
3.BufferedReader
1). 继承关系:
public class BufferedReader exrends Reader
2). 成员变量:
private Reader in
字符输入流节点流
private char cb[]
缓冲数组
3). 构造函数:
BufferedReader(Reader in)
//创建使用默认大小的输入缓冲区的缓冲字符输入流。
BufferedReader(Reader in, int sz)
//创建使用指定大小的输入缓冲区的缓冲字符输入流
4). 常用方法:
void close() //关闭流并释放与之相关联的任何系统资源。
Stream<String> lines() //返回一个 Stream ,其元素是从这个 BufferedReader读取的行。
void mark(int readAheadLimit) // 标记流中的当前位置。
boolean markSupported() //告诉这个流是否支持mark()操作。
int read() // 读一个字符
int read(char[] cbuf, int off, int len) //将字符读入数组的一部分。
String readLine() //读一行文字。包含行的内容的字符串,不包括任何行终止字符,如果已达到流的末尾,则为null.
boolean ready() //告诉这个流是否准备好被读取。如果缓冲区不为空,或者底层字符流准备就绪,则缓冲字符流就绪。如果下一个read()保证不阻止输入,则为True,否则为false。 请注意,返回false并不能保证下一次读取将被阻止。
void reset() //将流重置为最近的标记。
long skip(long n) //跳过字符
5). 使用方法代码展示:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class BufferedReaderDemo {
public static void main(String[] args) {
try {
//创建一个字符输入流对象
FileReader fileReader = new FileReader("D:\\test.txt");
//根据字符输入流构造一个字符输入缓冲流
BufferedReader bufferedReader = new BufferedReader(fileReader);
// char [] data=new char[512];
// //数据读取
// int len=-1;
// StringBuilder sb=new StringBuilder();
// while((len=bufferedReader.read(data))!=-1)
// {
// sb.append(new String(data,0,len));
// }
String s=null;
StringBuilder stringBuilder = new StringBuilder();
while ((s=bufferedReader.readLine())!=null) {
stringBuilder.append(s);
}
//读取数据完成后关闭流实例
bufferedReader.close();
fileReader.close();
//输出检验读取的数据
System.out.println(stringBuilder);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试结果:
4.BufferedWriter
1). 继承关系:
public class BufferedReader extends writer
2). 成员变量:
private Writer out
字符输出流节点流
private char cb[]
缓冲数组
3). 构造函数:
BufferedWriter(Writer out)
//创建使用默认大小的输出缓冲区的缓冲字符输出流。
BufferedWriter(Writer out, int sz)
//创建一个新的缓冲字符输出流,使用给定大小的输出缓冲区。
4). 常用方法:
void close() //关闭流,先刷新。
void flush() //刷新流。
void newLine() //换行
void write(char[] cbuf, int off, int len) //写入字符数组的一部分。
void write(int c) //写一个字符
void write(String s, int off, int len) //写一个字符串的一部分。
5). 使用方法代码展示:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
public class BufferedWriterDemo {
public static void main(String[] args) {
try {
//创建一个字符输出节点流实例
FileWriter fileWriter = new FileWriter("D:\\test.txt");
//根据字符输出流实例构造一个字节缓冲流实例
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
//定义一个想要插入的数据字符串
String s = "字符输出缓冲流测试!";
//字符输出缓冲流写入操作
bufferedWriter.write(s);
//刷新到内核空间的缓冲区
bufferedWriter.flush();
//输出完成后,关闭流实例
bufferedWriter.close();//关闭缓冲流时,也会刷新一次缓冲区
fileWriter.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
测试结果: