一.介绍
在我们学习字节流与字符流的时候,大家都进行过读取文件中数据的操作,读取数据量大的文件时,读取的速度会很慢,很影响我们程序的效率,那么,我想提高速度,怎么办?
Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度
缓冲流,根据流的分为分类字节缓冲流与字符缓冲流。
二.知识点介绍
1、高效流
2、字节缓冲流
3、普通流与缓冲流效率比较
4、缓冲流高效原理
5、字符缓冲流
6、包装思想
三.上课视频对用说明文档
1、高效流 (缓冲流)
高效字节流:BufferedInputStream/BufferedOutputStream 字节缓冲流
高效字符流:BufferedReader/BufferedWriter 字符缓冲流
高效流使用普通流对象作为构造方法参数。将普通流包装,提供高效的装饰。
关闭流时只需要关闭高效流即可。
2、字节缓冲流
字节缓冲流根据流的方向,共有2个
(1)写入数据到流中,字节缓冲输出流 BufferedOutputStream
(2)读取流中的数据,字节缓冲输入流 BufferedInputStream
它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度
2.1、字节缓冲输出流BufferedOutputStream
通过字节缓冲流,进行文件的读写操作 写数据到文件的操作
构造方法
(1)public BufferedOutputStream(OutputStream out)创建一个新的缓冲输出流,以将数据写入指定的底层输出流。
代码示例:
public class BufferedOutputStreamDemo01 {
public static void main(String[] args) throws IOException {
//写数据到文件的方法
write();
}
/*
* 写数据到文件的方法
* 1,创建流
* 2,写数据
* 3,关闭流
*/
private static void write() throws IOException {
//创建基本的字节输出流
FileOutputStream fileOut = new FileOutputStream("abc.txt");
//使用高效的流,把基本的流进行封装,实现速度的提升
BufferedOutputStream out = new BufferedOutputStream(fileOut);
//2,写数据
out.write("hello".getBytes());
//3,关闭流
out.close();
}
}
2.2、字节缓冲输入流 BufferedInputStream
刚刚我们学习了输出流实现了向文件中写数据的操作,那么,现在我们完成读取文件中数据的操作
构造方法
(1)public BufferedInputStream(InputStream in)
代码示例:
/*
* 从文件中读取数据
* 1,创建缓冲流对象
* 2,读数据,打印
* 3,关闭
*/
private static void read() throws IOException {
//1,创建缓冲流对象
FileInputStream fileIn = new FileInputStream("abc.txt");
//把基本的流包装成高效的流
BufferedInputStream in = new BufferedInputStream(fileIn);
//2,读数据
int ch = -1;
while ( (ch = in.read()) != -1 ) {
//打印
System.out.print((char)ch);
}
//3,关闭
in.close();
}
3、普通流与缓冲流效率比较
代码示例:
package cn.javahelp_01;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
/*
* 缓冲流与普通流 读取文件效率对比
*
*/
public class Demo {
public static void main(String[] args) throws IOException {
//普通字节流 fun();
//缓冲流 fun2();
fun3(); //普通数组
// 缓冲流数组 fun4();
}
private static void fun4() throws FileNotFoundException, IOException {
//创建 缓冲流对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("hi.jpg"));
long start = System.currentTimeMillis();
byte[] b = new byte[8*1024];
int len;
while ((len = bis.read(b))!=-1) {
}
bis.close();
long end = System.currentTimeMillis();
System.out.println("BufferedInputStream 使用数组 读取文件的时间:" + (end - start) + "毫秒"); //
}
private static void fun3() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("hi.jpg");
long start = System.currentTimeMillis();
byte[] b = new byte[ 8 *1024];
int len;
while ((len = fis.read(b)) != -1) {
}
fis.close();
long end = System.currentTimeMillis();
System.out.println("FileInputStream 使用数组 读取文件的时间:" + (end - start) + "毫秒"); //
}
private static void fun2() throws FileNotFoundException, IOException {
// 创建缓冲流 对象
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("hi.jpg"));
long start = System.currentTimeMillis();
int b;
while ((b = bis.read()) != -1) {
// System.out.print((char)b);
}
System.out.println();
bis.close(); // 关闭资源的时候 ,只需要关闭 缓冲流即可.
long end = System.currentTimeMillis();
System.out.println("BufferedInputStream 读取文件的时间:" + (end - start) + "毫秒"); // 225毫秒
}
private static void fun() throws FileNotFoundException, IOException {
// 使用 FileInputStream 读取 文件 . 打印在控制台.
FileInputStream fis = new FileInputStream("hi.jpg");
long start = System.currentTimeMillis();
int b;
while ((b = fis.read()) != -1) {
// System.out.print((char)b);
}
System.out.println();
fis.close();
long end = System.currentTimeMillis();
System.out.println("FileInputStream 读取文件的时间:" + (end - start) + "毫秒"); // 38995
// 毫秒
}
}
4、缓冲流高效原理
缓冲流之所以能够提高性能,主要是利用了在内存中开辟的buf空间来实现的,减少了直接消耗系统IO资源的次数,从而提高了性能
5、字符缓冲流BufferedWriter和BufferedReader
5.1、基本用法
(1)BufferedWriter:将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
(2)BufferedReader:从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。
代码示例:
public class Demo01BufferedStream {
public static void main(String[] args) throws IOException {
//创建输出缓冲流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
bw.write("hello");
//bw.flush();
bw.close();
//创建输入缓冲流对象
BufferedReader br = new BufferedReader(new FileReader("bw.txt "));
/*
//一次读写一个字符
int ch;
while((ch=br.read())!=-1){
System.out.print((char)ch);
}
*/
//一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
System.out.print(new String(chs,0,len));
}
//释放资源
br.close();
}
}
5.1.1、缓冲流复制文本文件的两种方式
代码示例:
public class Demo02CopyFile {
public static void main(String[] args) throws IOException {
//创建输入缓冲流对象
BufferedReader br = new BufferedReader(new FileReader("Demo01FileWriter.java"));
//创建输出缓冲流对象
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
//读写数据
/*
//一次读写一个字符
int ch;
while((ch=br.read())!=-1) {
bw.write(ch);
}
*/
//一次读写一个字符数组
char[] chs = new char[1024];
int len;
while((len=br.read(chs))!=-1) {
bw.write(chs,0,len);
}
//释放资源
bw.close();
br.close();
}
}
5.2、特殊方法:
高效字符流在普通IO方法的基础上,添加了readLine方法与newLine方法
(1)BufferedWriter
void newLine():写一个换行符,这个换行符由系统决定
(2)BufferedReader
String readLine():一次读取一行数据,但是不读取换行符
注意:
一切带缓冲的流在写出数据时,均需要刷新缓冲区调用flush方法,否则数据并没有真正写出到文件,而仍然停留在缓冲区。
在复制一行时,每次读取到的是这行的内容,虽然是以回车换行判断一行,但不包含最终的回车换行。可以使用”\r\n”来代表windows中的回车换行,但是却不通用,因为不同的操作系统,它的回车换行字符不一样。所以用newLine方法换行
5.2.1、字符高效输出流BufferedWriter(换行)
将文本写入字符输出流,高效各个字符,从而提供单个字符、数组和字符串的高效写入。
方法:
void newLine() 根据当前的系统,写入一个换行符 newLine方法可以跨凭台使用
代码示例:
/*
* BufferedWriter 字符高效输出流
* 方法
* public void newLine()写入一个行分隔符
*
* 需求: 通过高效输出流写入数据到文件
* 分析:
* 1,创建流对象
* 2,写数据
* 3,关闭流
*
*/
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
//创建流
//基本字符输出流
FileWriter fileOut = new FileWriter("file.txt");
//把基本的流进行包装
BufferedWriter out = new BufferedWriter(fileOut);
//2,写数据
for (int i=0; i<5; i++) {
out.write("hello");
out.newLine();
}
//3,关闭流
out.close();
}
}
5.2.2、字符高效输入流BufferedReader(读取一行)
从字符输入流中读取文本,高效各个字符,从而实现字符、数组和行的高效读取。
方法
public String readLine() 读取一个文本行,包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null
代码示例:
/*
* BufferedReader 字符高效输入流
*
* 方法:
* String readLine()
* 需求:从文件中读取数据,并显示数据
*/
public class BufferedReaderDemo {
public static void main(String[] args)throws IOException {
//1,创建流
BufferedReader in =new BufferedReader(new FileReader("file.txt"));
//2,读数据
//一次一个字符
//一次一个字符数组
//一次读取文本中一行的字符串内容
String line = null;
while( (line = in.readLine()) != null ){
System.out.println(line);
}
//3,关闭流
in.close();
}
}
5.2.3、缓冲流特殊功能复制文本文件
代码示例:
/*
* 采用高效的字符高效流,完成文本文件的赋值
*
* 数据源: file.txt
* 目的地: copyFile.txt
*
* 分析:
* 1,指定数据源, 是数据源中读数据,采用输入流
* 2,指定目的地,是把数据写入目的地,采用输出流
* 3,读数据
* 4,写数据
* 5,关闭流
*/
public class CopyTextFile {
public static void main(String[] args)throws IOException {
//1,指定数据源, 是数据源中读数据,采用输入流
BufferedReader in = new BufferedReader(new FileReader("file.txt"));
//2,指定目的地,是把数据写入目的地,采用输出流
BufferedWriter out = new BufferedWriter(new FileWriter("copyFile.txt"));
//3,读数据
String line = null;
while ( (line = in.readLine()) != null ) {
//4,写数据
out.write(line);
//写入换行符号
out.newLine();
}
//5,关闭流
out.close();
in.close();
}
}
6、包装思想
在高效流的源码中,我们发现普通流通过构造方法传入到高效流对象中,即高效流对象中包含了一个普通流对象。所以普通流中的方法高效流都存在,而高效流在普通流的基础上又添加了新的更为强大的方法,且添加了缓冲区效率也更高。
这相当于将普通流进行了包装,让原有类的功能变得更为强大。
在后边学习中,我们会遇到一些类似的包装类,其构造方法参数不是对应资源而是对应的普通流对象。