@[toc]
处理流之一:缓冲流
基础点知识
- 为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。
- 缓冲流要“套接”在相应的节点流之上,根据数据操作单位可以把缓冲流分为
字节:BufferedInputStream 和 BufferedOutputStream
字符:BufferedReader 和 BufferedWriter
- 缓冲流作用:提供流的读取、写入的速度(缓冲区)
- 缓冲流的关闭,先关闭外层的流,再关闭内层的流,但是在关闭外层流的同时,内层流也会自动的进行关闭,所以对于内层流的关闭,可以省略,也就是关闭流的顺序和打开流的顺序相反。只要关闭最外层流即可,关闭最外层流也 会相应关闭内层节点流
- 当使用BufferedInputStream读取字节文件时,BufferedInputStream会一次性从 文件中读取8192个(8Kb),存在缓冲区中,直到缓冲区装满了,才重新从文件中 读取下一个8192个字节数组。
- 向流中写入字节时,不会直接写到文件,先写到缓冲区中直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里。使用方法 flush()可以强制将缓冲区的内容全部写入输出流
- flush()方法的使用:手动将buffer中内容写入文件
- 如果是带缓冲区的流对象的close()方法,不但会关闭流,还会在关闭流之前刷 新缓冲区,关闭后不能再写出
缓冲流实现指定路径下非文本文件的复制(字节型)
@Test
public void test1(){
//1.造文件
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
File file1 = new File("柯基壁纸.jpg");
File file2 = new File("柯基壁纸3.jpg");
//2.造流
//2.1造文件流
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、写入
byte[] buffer = new byte[10];
int len=0;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
//bos.flush();//刷新缓冲区(write里面自带了,所以不用写,但是要知道作用)
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bis!=null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
//4.资源关闭
try {
if(bos!=null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//要求:先关闭外层的流,再关闭内层的流,但是在关闭外层流的同时,
// 内层流也会自动的进行关闭,关于内层流的关闭,可以省略
// fos.close();
// fis.close();
}
缓冲流与节点流读写速度对比
- 把缓冲流实现指定路径下非文本文件的复制的代码改为方法
public void copy(String srcPath,String destPath){
//1.造文件
BufferedInputStream bis = null;
BufferedOutputStream bos = null;
try {
File file1 = new File(srcPath);
File file2 = new File(destPath);
//2.造流
//2.1造文件流
FileInputStream fis = new FileInputStream(file1);
FileOutputStream fos = new FileOutputStream(file2);
//2.2造缓冲流
bis = new BufferedInputStream(fis);
bos = new BufferedOutputStream(fos);
//3.复制的细节:读取、写入
byte[] buffer = new byte[1024];
int len=0;
while((len=bis.read(buffer))!=-1){
bos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bis!=null)
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(bos!=null)
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//4.资源关闭
//要求:先关闭外层的流,再关闭内层的流,但是在关闭外层流的同时,
// 内层流也会自动的进行关闭,关于内层流的关闭,可以省略
// fos.close();
// fis.close();
}
时间测试:
@Test
public void testCopy(){
long startTime= System.currentTimeMillis();//开始时间
String srcPath="C:\\Users\\金士曼\\Desktop\\107-权限管理与访问控制.mp4";
String destPath="C:\\Users\\金士曼\\Desktop\\107-权限管理与访问控制2.mp4";
copy(srcPath,destPath);
long endTime=System.currentTimeMillis();
System.out.println("消耗的时间为"+(endTime-startTime));//2141
}
- 这里关于节点流的速度就不去测试了,肯定是比缓冲流耗费的时间多的,这里直接说结论
结论:缓存流提高读写速度的原因是因为内部提供了一个缓冲区
字符型:BufferedReader 和 BufferedWriter
很明显,BufferedReader 和 BufferedWriter对应的就是文件流里面的FileReader和FileWriter,处理的就是文本数据
步骤:
- 直接造文件造流,这里就没必要那么规范了
- 去读取和输出
- 流的关闭
代码:
@Test
public void test1(){
BufferedReader br= null;
BufferedWriter bw= null;
try {
//1. 造文件造流,这里就没必要那么规范了
br = new BufferedReader(new FileReader(new File("hello.txt")));
bw = new BufferedWriter(new FileWriter(new File("hello7.txt")));
//2. 去读取和输出
//其它方法:readLine(),返回一整行数据,如果没有则返回null
String data;
while ((data=br.readLine())!=null){
bw.write(data+"\n");//不包含换行符
/*方法二
bw.write(data);
bw.newLine();//提供换行的操作
*/
}
/*char[] chars = new char[10];
int len;
while ((len=br.read(chars))!=-1){
bw.write(chars,0,len);
}*/
} catch (IOException e) {
e.printStackTrace();
} finally {
//3. 流的关闭
try {
if (br!=null)
br.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if (bw!=null)
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
练习题
题目:获取文本上每个字符出现的次数(提示:遍历文本的每一个字符;字符及出现的次数保存在Map中;将Map中数据写入文件)
代码:
package com.jsm.IO_03;
import org.junit.Test;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* 练习3:获取文本上字符出现的次数,把数据写入文件
*
* 思路:
* 1.遍历文本每一个字符
* 2.字符出现的次数存在Map中
*
* Map<Character,Integer> map = new HashMap<Character,Integer>();
* map.put('a',18);
* map.put('你',2);
*
* 3.把map中的数据写入文件
*
* @author shkstart
* @create 2019 下午 3:47
*/
public class WordCount {
/*
说明:如果使用单元测试,文件相对路径为当前module
如果使用main()测试,文件相对路径为当前工程
*/
@Test
public void testWordCount() {
FileReader fr = null;
BufferedWriter bw = null;
try {
//1.创建Map集合
Map<Character, Integer> map = new HashMap<Character, Integer>();
//2.遍历每一个字符,每一个字符出现的次数放到map中
fr = new FileReader("dbcp.txt");
int c = 0;
while ((c = fr.read()) != -1) {
//int 还原 char
char ch = (char) c;
// 判断char是否在map中第一次出现
if (map.get(ch) == null) {
map.put(ch, 1);
} else {
map.put(ch, map.get(ch) + 1);
}
}
//3.把map中数据存在文件count.txt
//3.1 创建Writer
bw = new BufferedWriter(new FileWriter("wordcount.txt"));
//3.2 遍历map,再写入数据
Set<Map.Entry<Character, Integer>> entrySet = map.entrySet();
for (Map.Entry<Character, Integer> entry : entrySet) {
switch (entry.getKey()) {
case ' ':
bw.write("空格=" + entry.getValue());
break;
case '\t'://\t表示tab 键字符
bw.write("tab键=" + entry.getValue());
break;
case '\r'://
bw.write("回车=" + entry.getValue());
break;
case '\n'://
bw.write("换行=" + entry.getValue());
break;
default:
bw.write(entry.getKey() + "=" + entry.getValue());
break;
}
bw.newLine();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关流
if (fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bw != null) {
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}