重点
1.带缓冲的字节输入输出流
1.1 BufferedInputStream
BufferedInputStream内置了一个缓冲区(数组)
当使用BufferedInputStream读取一个字节时,BufferedInputStream会一次性从文件中读取8192个(8Kb), 存在缓冲区中,直到缓冲区装满了, 才重新从文件中读取下一个8192个字节数组
1.2 BufferedOutputStream
BufferedOutputStream也内置了一个缓冲区(数组)
向流中写入字节时, 不会直接写到文件, 先写到缓冲区中直到缓冲区写满, BufferedOutputStream才会把缓冲区中的数据一次性写到文件里
1.3带Buffered的流和自己写的字节数组缓冲对比
自己写数组会略胜一筹,因为读和写操作的是同一个数组,而Buffered操作的是两个数组
6.4BufferedOutputStream的flush和close方法的区别
flush()方法
1.用来刷新缓冲区的,把内部buf[] 变量的数据写入文件,刷新后可以再次写入数所
close()方法
2.用来关闭流释放资源的
3.如果是带缓冲区的流对象的close()方法,不但会关闭流,还会再关闭流之前刷新缓冲区,关闭后不能再写出
3.字节流读写中文乱码问题
3.1字节流读取中文
字节流在读中文的时候有可能会读到半个中文,造成乱码
解决方案:Java提供一个类Reader(字符流)
3.2字节流写入中文
使用字节流写入中文必须将字符串转换成字节数组
如果想添加换行添加write("\r\n".getBytes())代码
将字符串写入文件中,也可以指定写入字符的码表 如getBytes(“UTF-8”)
4.流的标准处理异常方式
4.1jdk1.6以前的处理方式
读写的操作放在try里面
关闭流的操作放finally
4.2jdk1.7以后的处理方式
实现方式:
1.把流对象的声明放在try() 括号里面
2.操作流【读写数据】的代码放在花括号里面
3.这样写不用关闭流,java自动关闭流
4.在try的括号里的对象,必须是实现AutoCloseable的接口
5.字符流
5.1什么是字符流
字符流是可以直接读写字符的IO流
使用字符流从文件中读取字符时, 需要先读取到字节数据, 然后转为字符.
使用字符流往文件写入字符时, 需要把字符转为字节再写入文件.
5.2字符流有两大派
Reader和Writer,这两个类是抽象类,一般使用它们的子类
FileReader和FileWriter
5.3FileReader的使用
FileReader 用于读取字符,调用read方法的时候,是读取一个字符
read方法的返回值是int,它是把char 转成int
以后读纯文本文件,使用FileReader这个类,为什么?因为我们不用考虑乱码问题
public static void test1() throws FileNotFoundException, IOException {
//FileReader
/**
* FileReader 用于读取字符
*/
//1.创建对象
FileReader reader = new FileReader("a.txt");
//2.读取数据
/**
* reader.read() : 先读取到字节数据, 然后转为字符
*/
/* System.out.println((char)reader.read());
System.out.println((char)reader.read());
System.out.println((char)reader.read());
System.out.println((char)reader.read());
System.out.println((char)reader.read());
System.out.println(reader.read());*/
int c;
while((c = reader.read()) != -1){
System.out.println((char)c);
}
//3.关闭流
reader.close();
}
5.4 FileWriter的使用
public static void main(String[] args) throws Exception {
//FileWiter 文件写入流、文件写入字符流
//案例:使用FileWiter往一个文件a.txt写内容
//1.创建writer对象
FileWriter writer = new FileWriter("a.txt");
//2.写内容
writer.write("你好!");
writer.write("\r\n");
writer.write("你好!");
writer.write("\r\n");
writer.write("你好!");
writer.write("\r\n");
writer.write("你好!");
//3.关闭
writer.close();
}
练习题
1.拷贝图片【优化一】
一次性读取文件所有数据,一次性将所有数据写入文件
这种方式在大文件下不建议使用
FileInputStream有个available()方法,返回文件大小
2.拷贝图片【优化二】
这种方式开发中建议经常使用
拷由文件时应该使用缓冲区思想、或者杯子思想
缓冲区思想、杯子思想是指把文件数据先读取到一个字节数组中【byte buf[]】,然后再把字节数组中的数据写入文件中
字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多
public class Demo01 {
public static void main(String[] args) throws IOException {
//案例:拷贝图片【优化二、这种方式开发中建议经常使用】
/**
* 1.每次只读一个字节,又觉得太慢
* 2.一次性读一个文件的所有数据,又怕内存装不下
* 内存只有2G,视频3G,这样就会内存溢出
*
* 3.最终解决方法:折中,定义每次读8KB
*
*/
//1.输入流
FileInputStream fis = new FileInputStream("C:/Users/10301/Desktop/a/cm.jpg");
//2.输出流
FileOutputStream fos = new FileOutputStream("C:/Users/10301/Desktop/a/cm-副本2.jpg");
//3.定义个8kb字节数组,也叫缓冲区流
byte[] bytes = new byte[1024 * 8];
int len = 0;
int i = 0;
while( (len = fis.read(bytes)) != -1){
i++;
//4.写入文件
fos.write(bytes,0,len);
}
System.out.println("读取的次数:" + i);
//5.关闭流
fis.close();
fos.close();
}
}
3.使用缓冲字节流读取数据
/* BufferedInputStream和BufferedOutputStream
>这两个流是内置了缓冲区流,也就是说内部有一个字节数组
>这个两个类没有前面我们写的好用,因为它内部每次读8kb字节,如果想读80kb,没办法
*/
//案例:拷贝音频文件
//1.创建缓冲输入流
FileInputStream fis = new FileInputStream(“C:/Users/10301/Desktop/a/ghsy.mp3”);
BufferedInputStream bis = new BufferedInputStream(fis);
//2.创建缓冲输出流
FileOutputStream fos = new FileOutputStream("C:/Users/10301/Desktop/a/ghsy-副本.mp3");
BufferedOutputStream bos =new BufferedOutputStream(fos);
//3.输入流读数据、输出流写数据
int b = 0;
// bis.read()方法,内部会读8kb数据
while( (b = bis.read()) != -1){
bos.write(b);//内部会写8kb数据
}
//4.关流,只需要关缓冲流,文件流不用关
bis.close();//【内部会关文件流输入流】
bos.close();//【内部会关文件流输出流】
System.out.println("音频拷贝完成...");
原理图:
4.一个字节的拷贝音频文件
5.字节流练习题
5.1图片加密
5.2根据路径拷贝文件
- 根据用户输入的文件[图片]拷贝文件到当前项目目录
public static void main(String[] args) throws IOException {
//练习:根据用户输入的文件[图片]拷贝文件到当前项目目录
//C:/Users/10301/Desktop/a/cm2.jpg
//1.获取用户输入的文件路径
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个文件的路径[请不要输入文件夹路径]:");
String path = scanner.nextLine();
//2.判断这个路径是否为文件
File file = new File(path);
if(file.isDirectory()){
System.out.println("您输入的路径不是一个文件");
return;
}
//3.如果是文件就拷贝
//3.1 输入流
FileInputStream fis = new FileInputStream(path);
//3.2输出流
FileOutputStream fos = new FileOutputStream(file.getName());
//3.3读写【性能】
byte[] buf = new byte[8 * 1024];
int len = 0;
while((len = fis.read(buf)) != -1){
fos.write(buf, 0, len);
}
//3.4关流
fis.close();
fos.close();
System.out.println("文件拷贝完成...");
}
5.3录入数据拷贝到文件
根据用户在键盘中输入的内容,然后写到一个文件中去
public static void main(String[] args) throws IOException {
/**
* 根据用户在键盘中输入的内容,然后写到一个文件中去
*/
//1.创建一个文件输出流
FileOutputStream fos = new FileOutputStream("new.txt");
//2.创建一个Scanner对象
Scanner scanner = new Scanner(System.in);
System.out.println("请输入需要录入内容...输入quit代表退出");
//3.通过死循环来获取用户输入【当输入quit,代表不录入】
while(true){
//获取用户的输入
String line = scanner.nextLine();
//退出循环
if(line.equals("quit")){
break;
}
//写入文件
fos.write(line.getBytes());
//换行
fos.write("\r\n".getBytes());
}
//4.关流
fos.close();
}
6.字符流的拷贝
需求:将a.txt文件内容拷。贝到b.txt文件中,必须使用字符流
思路:用FileReader读字符,用FileWriter写字符
方式一:每次读写一个字符
//1.创建 “读取流” 对象
FileReader reader = new FileReader("a.txt");
//2.创建 "写入流" 对象
FileWriter writer = new FileWriter("b.txt");
//3.读取和写入
int c = 0;
while((c = reader.read()) != -1){
writer.write(c);
}
//4.关闭流
reader.close();
writer.close();
方式一:每次读写多个字符
//1.创建 “读取流” 对象
FileReader reader = new FileReader("a.txt");
//2.创建 "写入流" 对象
FileWriter writer = new FileWriter("b.txt");
//3.读取和写入【缓冲思想】
char[] buf = new char[8 * 1024];
int len = 0;
while( (len = reader.read(buf)) != -1){
writer.write(buf, 0, len);
}
//4.关闭流
reader.close();
writer.close();
面试题
总结
今天学习了BufferedInputStream、BufferedOutputStream能灵活的使用它们完成文件的读取,复制等操作,学习了杯子思想(即缓冲思想)。