了解了IO
流,再说一说一些更强大的流。比如能够高效读写的缓冲流,能够转换编码的转换流,能够持久化存储对象的序列化流等等。这些功能更为强大的流,都是在基本的流对象基础之上创建而来的,就像穿上铠甲的武士一样,相当于是对基本流对象的一种增强。咱们先说说缓冲流。
1.1 概述
缓冲流,也叫高效流,是对4个基本的FileXxx
流的增强,所以也是4个流,按照数据类型分类:
-
字节缓冲流:
BufferedInputStream
,BufferedOutputStream
-
字符缓冲流:
BufferedReader
,BufferedWriter
缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组,通过缓冲区读写,减少系统IO
次数,从而提高读写的效率。
1.2 字节缓冲流
构造方法
-
public BufferedInputStream(InputStream in)
:创建一个 新的缓冲输入流。 -
public BufferedOutputStream(OutputStream out)
:创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("bis.txt"));
// 创建字节缓冲输出流
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
效率测试
查询API
,缓冲流读写方法与基本的流是一致的,我们通过复制大文件(5.21MB),测试它的效率。
- 基本流,代码如下:
package com.dcxuexi.java24;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
/***
* @Title BufferedDemo
* @Description TOTD
* @Auter DongChuang
* @Date 2022/12/13 22:15
* @Version 1.0.0
*/
public class BufferedDemo {
public static void main(String[] args) throws IOException {
// 记录开始时间
long start = System.currentTimeMillis();
// 创建流对象
FileInputStream fis = fis = new FileInputStream("D:\\java\\javaCode\\dingtalk_downloader.exe");
FileOutputStream fos = fos = new FileOutputStream("D:\\java\\javaCode\\File\\dingtalk_downloader.exe");
// 读写数据
int b;
while ((b = fis.read()) != -1) {
fos.write(b);
}
fos.close();
fis.close();
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:" + (end - start) + " 毫秒");
}
}
- 缓冲流,代码如下:
package com.dcxuexi.java24;
import java.io.*;
/***
* @Title BufferedDemo02
* @Description TOTD
* @Auter DongChuang
* @Date 2022/12/13 22:35
* @Version 1.0.0
*/
public class BufferedDemo02 {
public static void main(String[] args) throws IOException {
// 记录开始时间
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\java\\javaCode\\dingtalk_downloader.exe"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\java\\javaCode\\File\\dingtalk_downloader02.exe"));
// 读写数据
int b;
while ((b = bis.read()) != -1) {
bos.write(b);
}
// 释放资源
bos.close();
bis.close();
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
}
}
如何更快呢?
使用数组的方式,代码如下:
public class BufferedDemo02 {
public static void main(String[] args) throws IOException {
// 记录开始时间
long start = System.currentTimeMillis();
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("D:\\java\\javaCode\\dingtalk_downloader.exe"));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\java\\javaCode\\File\\dingtalk_downloader03.exe"));
// 读写数据
int len;
byte[] bytes = new byte[8*1024];
while ((len = bis.read(bytes)) != -1) {
bos.write(bytes,0,len);
}
// 释放资源
bos.close();
bis.close();
// 记录结束时间
long end = System.currentTimeMillis();
System.out.println("缓冲流复制时间:"+(end - start)+" 毫秒");
}
}
1.3 字符缓冲流
构造方法
-
public BufferedReader(Reader in)
:创建一个 新的缓冲输入流。 -
public BufferedWriter(Writer out)
:创建一个新的缓冲输出流。
构造举例,代码如下:
// 创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("br.txt"));
// 创建字符缓冲输出流
BufferedWriter bw = new BufferedWriter(new FileWriter("bw.txt"));
特有方法
字符缓冲流的基本方法与普通字符流调用方式一致,不再阐述,我们来看它们具备的特有方法。
-
BufferedReader
:public String readLine()
: 读一行文字。 -
BufferedWriter
:public void newLine()
: 写一行行分隔符,由系统属性定义符号。
readLine
方法演示,代码如下:
package com.dcxuexi.java24;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
/***
* @Title BufferedReaderDemo
* @Description TOTD
* @Auter DongChuang
* @Date 2022/12/14 20:19
* @Version 1.0.0
*/
public class BufferedReaderDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedReader bufferedReader = new BufferedReader(new FileReader("D:\\java\\javaCode\\bufferedReader\\bufferedReader.txt"));
// 定义字符串,保存读取的一行文字
String line = null;
int i = 1;
// 循环读取,读取到最后返回null
while ((line = bufferedReader.readLine())!=null){
System.out.println("第"+ i +"行-->"+line);
i++;
}
// 释放资源
bufferedReader.close();
}
}
newLine
方法演示,代码如下:
package com.dcxuexi.java24;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
/***
* @Title BufferedWriterDemo
* @Description TOTD
* @Auter DongChuang
* @Date 2022/12/14 20:29
* @Version 1.0.0
*/
public class BufferedWriterDemo {
public static void main(String[] args) throws IOException {
// 创建流对象
BufferedWriter bufferedWriter = new BufferedWriter(new FileWriter("D:\\java\\javaCode\\bufferedReader\\bufferedWriter.txt"));
bufferedWriter.write("石家庄赵子龙"); // 写出数据
bufferedWriter.newLine();// 写出换行
bufferedWriter.write("包头吕布"); // 写出数据
bufferedWriter.newLine();// 写出换行
bufferedWriter.write("合肥包拯"); // 写出数据
// 释放资源
bufferedWriter.close();
}
}
1.4 练习:文本排序(春江花月夜)
请将文本信息恢复顺序。
18.江畔何人初见月?江月何年初照人?
25.此时相望不相闻,愿逐月华流照君。
17.江天一色无纤尘,皎皎空中孤月轮。
19.人生代代无穷已,江月年年望相似。
12.【作者】张若虚 【朝代】唐
21.白云一片去悠悠,青枫浦上不胜愁。
28.江水流春去欲尽,江潭落月复西斜。
29.斜月沉沉藏海雾,碣石潇湘无限路。
26.鸿雁长飞光不度,鱼龙潜跃水成文。
14.滟滟随波千万里,何处春江无月明!
20.不知江月待何人,但见长江送流水。
11.春江花月夜
22.谁家今夜扁舟子?何处相思明月楼?
13.春江潮水连海平,海上明月共潮生。
30.不知乘月几人归,落月摇情满江树。
23.可怜楼上月裴回,应照离人妆镜台。
24.玉户帘中卷不去,捣衣砧上拂还来。
15.江流宛转绕芳甸,月照花林皆似霰;
27.昨夜闲潭梦落花,可怜春半不还家。
16.空里流霜不觉飞,汀上白沙看不见。
案例分析
- 逐行读取文本信息。
- 解析文本信息到集合中。
- 遍历集合,按顺序,写出文本信息。
案例实现
package com.dcxuexi.java24;
import java.io.*;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;
/***
* @Title BufferedTest
* @Description TOTD
* @Auter DongChuang
* @Date 2022/12/14 20:43
* @Version 1.0.0
*/
public class BufferedTest {
public static void main(String[] args) throws IOException {
// 创建map集合,保存文本数据,键为序号,值为文字
HashMap<String, String> lineMap = new HashMap<>();
// 创建流对象
BufferedReader br = new BufferedReader(new FileReader("D:\\java\\javaCode\\bufferedReader\\gushi.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\java\\javaCode\\bufferedReader\\tangshi.txt"));
// 读取数据
String line = null;
while ((line = br.readLine())!=null){
// 解析文本
String[] split = line.split("\\.");
// 保存到集合
lineMap.put(split[0],split[1]);
}
// 释放资源
br.close();
Set<String> key = lineMap.keySet();
//创建TreeSet排序的lambda表达式; 相比于传统方式,代码量上有了很大的减少;
Set<String> treeSet = new TreeSet<String>(String::compareTo);
treeSet.addAll(key);
// 遍历map集合
for (String keyStr : treeSet) {
// 写出拼接文本
bw.write(lineMap.get(keyStr));
// 写出换行
bw.newLine();
}
// 释放资源
bw.close();
}
}