文章目录
前言
能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,相当于是对基本流对象的一种增强。
缓冲流是对4个基本的 FileXxx 流的增强,所以也是4个流,按照数据类型分类:
字节缓冲流: BufferedInputStream , BufferedOutputStream
字符缓冲流: BufferedReader , BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO次数,从而提高读写的效率。
提示:以下是本篇文章正文内容,下面案例可供参考
一、字节缓冲流
1. 字节输出缓冲流(写出)
BufferedOutputStream 继承OutputStream,操作时还是使用OutputStream的write方法。
构造方法:
BufferedOutputStream(OutputStream out) 参数要一个基本的流,最终靠基本的流去操作文件。
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
/**
* 字节输出缓冲流(写)
* new 缓冲流(new 基本流)
*/
public class demo01 {
public static void main(String[] args) throws Exception {
/**
* 参数要一个基本的流,最终靠基本的流去操作文件
*/
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day_11/src/com/hntou/IO/Output/a.txt"));
/**
* 追加 BufferedOutputStream 的构造方法第二个参数没有boolean类型
* 所以追加模式的true需要加载原来流上加
*/
//BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day_11/src/com/hntou/IO/Output/a.txt",true));
//写出一个字节
bos.write(97);
//写出一个字节数组
byte[] bytes = {65,66,67,68};
bos.write(bytes);
//写出一个字节数组的一部分
bos.write(bytes,0,2);
//关闭流(不然会丢失数据)
bos.close();
}
}
2. 字节输入缓冲流(读入)
BufferedInputStream 继承InputStream,操作还是使用InputStream的read方法。
构造方法:BufferedInputStream(InputStream in) 参数要一个基本的流,靠基本的流去操作文件。
2.1 输入一个字节
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 输入缓冲流(读)
* new 换冲流(new基本流)
*/
public class demo01 {
public static void main(String[] args) throws Exception {
//1.创建缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day_11/src/com/hntou/IO/Output/a.txt"));
//2.读数据
System.out.println((char) bis.read());
//3.关闭流
bis.close();
}
}
2.2 循环输入一个字节
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 循环读取一个字节
*/
public class demo02 {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day_11/src/com/hntou/IO/Output/a.txt"));
int ch;
while((ch=bis.read())!=-1){
System.out.print((char) ch);
}
}
}
2.3 输入一个字节数组
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 读取一个字节数组
*/
public class demo03 {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day_11/src/com/hntou/IO/Output/a.txt"));
byte[] bytes = new byte[2];
int len = bis.read(bytes);
String str = new String(bytes,0,len);
System.out.println(str);
bis.close();
}
}
2.4 循环输入一个字节数组
import java.io.BufferedInputStream;
import java.io.FileInputStream;
/**
* 循环读取一个字节数组
*/
public class demo04 {
public static void main(String[] args) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day_11/src/com/hntou/IO/Output/a.txt"));
byte[] bytes = new byte[2];
int len;
/**
* 每次读两个存入缓冲区
*/
while((len =bis.read(bytes))!=-1){
System.out.print(new String(bytes,0,len));
}
}
}
二、字符缓冲流
1. 字符输出缓冲流(写出)
BufferedWriter 继承了Writer,可以使用父类Writer中的write方法。
构造方法: BufferedWriter(Writer out) 参数要传入基本流,靠基本流来操作文件。
特有方法:newline() 换行
import java.io.BufferedWriter;
import java.io.FileWriter;
/**
* 字符输出缓冲流(写)
*/
public class demo01 {
public static void main(String[] args) throws Exception {
//创建字符输出缓冲流
BufferedWriter bw = new BufferedWriter(new FileWriter("day_11/src/com/hntou/IO/Reader/b.txt"));
//写出一个字符
bw.write(97);
//换行(字符缓冲输出流独有方法)
bw.newLine();
//写出字符数组
char[] chars = {97,98,99,100};
bw.write(chars);
//写出字符数组的一部分
bw.write(chars,0,2);
bw.newLine();
//写出字符串
bw.write("字符串");
//关闭流
bw.close();
}
}
2. 字符输入缓冲流(读入)
BufferedReader 继承了Reader,可以使用父类Reader中的read方法。
构造方法: BufferedReader(Reader in) 参数要传入基本流,靠基本流来操作文件。
特有方法:String readLine() 读取一行数据返回,读不到时返回null。
1.1 输入一个字符
import java.io.BufferedReader;
import java.io.FileReader;
/**
* 字符输入缓冲流(读)
*/
public class demo01 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Reader/b.txt"));
//读取一个字符
System.out.println((char) br.read());
br.close();
}
}
1.2 循环输入一个字符
import java.io.BufferedReader;
import java.io.FileReader;
/**
* 循环读取一个字符
*/
public class demo02 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Reader/b.txt"));
//循环读取一个字符
int ch;
while ((ch = br.read()) != -1) {
System.out.print((char) ch);
}
br.close();
}
}
1.3 输入一个字符数组
/**
* 读取一个字符数组
*/
public class demo03 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Reader/b.txt"));
char[] chars = new char[2];
int len = br.read(chars);
String str = new String(chars,0,len);
System.out.println(str);
br.close();
}
}
1.4 循环输入一个字符数组
import java.io.BufferedReader;
import java.io.FileReader;
/**
* 循环读取一个字符数组
*/
public class demo04 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Reader/b.txt"));
char[] chars = new char[2];
int len;
while((len = br.read(chars))!=-1){
System.out.print(new String(chars,0,len));
}
br.close();
}
}
1.5 独有方法readLine()
import java.io.BufferedReader;
import java.io.FileReader;
/**
* 读取一行
*/
public class demo05 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Reader/b.txt"));
//System.out.println(br.readLine());
/**
* 循环读取一行,读不到返回null
*/
String s;
while((s= br.readLine())!=null){
System.out.println(s);
}
br.close();
}
}
三、字符流解析文件案例
需求:
解析出“用户列表.txt”文件中的用户姓名和年龄,封装成User对象,保存到集合中,并对年龄进行升序排序。
分析:
创建字符输入缓冲流BufferedReader。
定义User类,提供name和age属性。
循环读取一行数据,将每行数据切割出姓名和年龄,每行数据对应一个User对象。
创建ArrayList集合,存储User对象。
使用Collections工具类实现集合元素升序排序。
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
/**
* 使用字符流解析文件
*
* 解析出“用户列表.txt”文件中的用户姓名和年龄,封装成User对象,保存到集合中,并对年龄进行升序排序。
* 分析:
* 创建字符输入缓冲流BufferedReader。
* 定义User类,提供name和age属性。
* 循环读取一行数据,将每行数据切割出姓名和年龄,每行数据对应一个User对象。
* 创建ArrayList<User>集合,存储User对象。
* 使用Collections工具类实现集合元素排序。
*/
public class demo01 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("day_11/src/com/hntou/IO/Case/user.txt"));
ArrayList<User> list = new ArrayList<>();
String s;
while ((s=br.readLine())!=null){
//读取一行之后分割数据 张三 18
String[] split = s.split("=");
//创建User对象加入集合
//因为User构造方法第二个参数是Integer类型,分割出来的是字符串类型,所以需要包装为Integer类型
list.add(new User(split[0],Integer.valueOf(split[1])));
}
br.close();
Collections.sort(list,(o1,o2)->o1.getAge()-o2.getAge());
System.out.println(list);
}
}
四、缓冲流性能对比案例
需求:使用四种方式完成文件复制(测试数据为1M)
字节流四种方式复制文件:
基本流读取一个字节&&缓冲流读取一个字节
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CopyDemo {
public static void main(String[] args) throws Exception {
//测试运行效率
long start = System.currentTimeMillis();
test1();
//test2();
long end = System.currentTimeMillis();
System.out.println(end-start+"ms");
}
//基本流读写一个字节(桌面拷贝到当前项目路径下)
public static void test1() throws Exception{
//读
FileInputStream fis = new FileInputStream("/Users/hebinyang/Desktop/test.pdf");
//写
FileOutputStream fos = new FileOutputStream("day_11/src/com/hntou/IO/Case/test.pdf");
int ch ;
while((ch=fis.read())!=-1){
fos.write(ch);
}
fis.close();
fos.close();
}
//缓冲流读写一个字节(桌面拷贝到当前项目路径下)
public static void test2() throws Exception{
//读
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("/Users/hebinyang/Desktop/test.pdf"));
//写
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("day_11/src/com/hntou/IO/Case/test.pdf"));
byte[] bytes = new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fis.close();
fos.close();
}
}
字节基本流一次一个字节copy一个1.4M的文件用了3064ms
字节缓冲流一次一个字节copy一个1.4M的文件用了6ms
基本流读取一个字节数组&&字节缓冲流读取一个字节数组
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class CopyDemo {
public static void main(String[] args) throws Exception {
//测试运行效率
long start = System.currentTimeMillis();
//test3();
//test4();
long end = System.currentTimeMillis();
System.out.println(end-start+"ms");
}
//基本流读写一个字节数组(桌面拷贝到当前项目路径下)
public static void test3() throws Exception{
//读
FileInputStream fis = new FileInputStream("/Users/hebinyang/Desktop/test.pdf");
//写
FileOutputStream fos = new FileOutputStream("day_11/src/com/hntou/IO/Case/test.pdf");
byte[] bytes = new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
fos.write(bytes);
}
fis.close();
fos.close();
}
//缓冲流读写一个字节数组(桌面拷贝到当前项目路径下)
public static void test4() throws Exception{
//读
BufferedInputStream fis = new BufferedInputStream(new FileInputStream("/Users/hebinyang/Desktop/test.pdf"));
//写
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream("day_11/src/com/hntou/IO/Case/test.pdf"));
byte[] bytes = new byte[1024];
int len;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fis.close();
fos.close();
}
}
基本流读取一个字节数组用了9ms
这里可以发现基本流用数组读写已经比单个字节读写效率提升很多了。
缓冲流读取一个字节数组用了6ms
这里可以发现读写字符数组无论是缓冲流还是基本流的差距不是很大。
五、总结
1.缓冲流性能对比:
- 一个文件每次读写一个字节,使用缓冲流,可以明显提高效率。
- 一个文件每次读写一个字节数组,基本流和缓冲流的差别不大。
- 缓冲流续写效率高,尽量使用缓冲流去代替基本流的使用。
2.字符缓冲流为什么提高了操作数据的性能。
- 字符缓冲流自带8K的缓冲区
- 可以提高原始自负流读写数据的性能。
- 字符缓冲流的新增功能。(public BufferedReader(Reader r) 多个readLine() 按照行读取的功能。 public BufferedWriter(Writer w) 多了newLine() 换行的功能。)