文本文件(.txt、.java、.c、.cpp)-------字符流(FileReader、FileWriter)
非文本文件(.jpg、.mp3、.mp4、.doc、.ppt)------字节流(FileInputStream、FileOutputStream)
一、FileReader
1.每次读取一个字符,循环读取文件中的字符
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Demo02 {
public static void main(String[] args) throws IOException {
//利用FileReader读取文件:d:\test.txt “abc老师”
//1.将文件封装为File类的对象
File file = new File("d:"+File.separator+"javatest"+File.separator+"test.txt");
//2.创建FileReader流的对象,传入file文件
FileReader fr = new FileReader(file); //异常先在方法上抛出
//3.读取文件中的数据:利用read()方法,返回的是int类型,于是使用int类型接收
//1)一个一个字符读取
/*int n = fr.read();
//System.out.println(n); //97,读取到的是第一个字符a的ascii码
//由于read()一次只能读取一个字符,所以需要循环读取,当读到文件结尾没有字符可以读取时,会返回-1
while (n!=-1){
System.out.println(n);
n = fr.read();
}*/
//上面的循环读取更简洁的代码写法,将n=fr.read()写在while循环中
int n;
while ((n=fr.read())!=-1){
System.out.println(n);
}
}
}
2.每次读取多个字符,循环读取文件中的字符(缓冲数组)
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class Demo02 {
public static void main(String[] args) throws IOException {
//利用FileReader读取文件:d:\test.txt “abc老师”
//1.将文件封装为File类的对象
File file = new File("d:"+File.separator+"javatest"+File.separator+"test.txt");
//2.创建FileReader流的对象,传入file文件
FileReader fr = new FileReader(file); //异常先在方法上抛出
//3.读取文件中的数据:利用read()方法,返回的是int类型,于是使用int类型接收
//2)利用缓冲数组,多个字符一起读取,这里一次性读取5个
//test.txt:“abchello老师你好“
char[] ch = new char[5];
//每次读取ch的长度个也就是5个字符并且存放入数组,这里会返回ch数组的元素数量。
//也就是说,如果ch中有5个元素,则返回5,如果只有2个元素就返回2
int len;
while ((len=fr.read(ch))!=-1) { //fr.read(ch)如果不放在while的()里会导致一直不停的读取
for (int i = 0; i < len; i++) { //每次读取数组中0到len-1的下标的字符
System.out.print(ch[i]);
//len=fr.read(ch) //如果不放在while的()内也可以放在循环中
}
/*//也可以直接将数组转换成字符串
String str = new String(ch,0,len);//转换数组中从下标[0,len)的字符
System.out.print(str);*/
}
}
}
二、FileWriter
1.每次写入一个字符
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
//1.将目标文件并封装为对象
File file = new File("d:\\javatest\\new.txt");
//2.创建FileWriter类,并传入目标文件对象
//如果new.txt不存在,会自动创建,如果存在,则会覆盖原内容
FileWriter fw = new FileWriter(file);
/*//file后的append参数true表示追加,false表示覆盖
FileWriter fw = new FileWriter(file,true); //添加的内容会追加到file后面
FileWriter fw = new FileWriter(file,false); //添加的内容会覆盖到file的内容*/
//3.将数据输出到目标文件:write()方法
String s="abchello老师你好";
//1)一个一个字符输入到文件
for (int i = 0; i < s.length(); i++) {
//System.out.println(s.charAt(i));//可以返回字符串中的每一个字符
fw.write(s.charAt(i));
}
}
}
2.每次写入多个字符(缓冲数组)
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo03 {
public static void main(String[] args) throws IOException {
//1.将目标文件并封装为对象
File file = new File("d:\\javatest\\new.txt");
//2.创建FileWriter类,并传入目标文件对象
//如果new.txt不存在,会自动创建,如果存在,则会覆盖原内容
FileWriter fw = new FileWriter(file);
/*//file后的append参数true表示追加,false表示覆盖
FileWriter fw = new FileWriter(file,true); //添加的内容会追加到file后面
FileWriter fw = new FileWriter(file,false); //添加的内容会覆盖到file的内容*/
//3.将数据输出到目标文件:write()方法
String s="abchello老师你好";
//2)利用缓冲数组将多个字符一起输入到文件
//将字符串转为数组
char[] chars = s.toCharArray();
//直接将数组写入到文件中
fw.write(chars);
//4.关闭流
fw.close();
}
}
三、FileReader和FileWriter实现读取文件并写入到另一个文件
1.每次写入一个字符
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo04 {
public static void main(String[] args) throws IOException {
//1.将源文件和目标文件都封装为对象
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
//2.创建FileReader和FileWriter对象接收源文件和目标文件
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//3.读取源文件
//1)一个一个写入
int n;
while ((n=fr.read())!=-1){
fw.write(n); //fr.read()读取一个字符,fw.write()写入一个字符
}
//4.关闭流(后用先关)
fw.close();
fr.close();
}
}
2.每次写入多个字符(缓冲数组)
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo04 {
public static void main(String[] args) throws IOException {
//1.将源文件和目标文件都封装为对象
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
//2.创建FileReader和FileWriter对象接收源文件和目标文件
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//3.读取源文件
//2)5个一次性读取,放入数组,一次性写入数组
char[] ch = new char[5];
int len;
while ((len=fr.read(ch))!=-1){
fw.write(ch,0,len); //将缓冲数组里的有效元素,一次性写入
}
//4.关闭流(后用先关)
fw.close();
fr.close();
}
}
3.将读取到的多个数组的元素先转换为String后一次性写入
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Demo04 {
public static void main(String[] args) throws IOException {
//1.将源文件和目标文件都封装为对象
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
//2.创建FileReader和FileWriter对象接收源文件和目标文件
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//3.读取源文件
//3)将数组的元素转换为String后写入
char[] ch = new char[5];
int len;
while ((len=fr.read(ch))!=-1){
String s = new String(ch, 0, len);
fw.write(s); //每一次将字符串s,一次性写入,
}
//4.关闭流(后用先关)
fw.close();
fr.close();
}
}
四、使用try/catch处理FileReader和FileWriter中的异常
1.先编写一段读取文件并写入另一个文件的代码,不处理异常
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
public class Demo05 {
public static void main(String[] args) {
//先编写一段读取文件并写入到另一个文件的代码
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
FileReader fr = new FileReader(src); //异常1
FileWriter fw = new FileWriter(tgt); //异常2
char[] ch = new char[5];
int len=fr.read(ch); //异常3
while (len!=-1) {
fw.write(ch,0,len); //异常4
}
}
}
2.开始逐个处理异常
对于异常,使用try/catch处理
1)对于new FileReader(src)和 new FileWriter(tgt)的异常可以进行合并
合并后代码如
2)对于fr.read(ch)和fw.write()的异常,可以看到都是IOException,与上面的异常相同,所以可以合并到上面的try中,就算异常不一样,也要把所有可能出现异常的语句放到try中,再添加缺少的异常。
3)对于close()产生的异常需要单独处理,且需要加上防止空指针异常的语句
五、FileInputStream和FileOutputStream实现读取文件并写入到另一个文件
1.为什么不用FileInputStream和FileOutputStream处理字符(文本文件)
1)对于utf-8存储的字符文件,底层英文字母占1个字节,但是汉字占3个字节,读取时每个汉字会返回3个字节,这样读取没有意义
2)对于读取到的字节,按道理应该使用byte类型来接收,但是byte类型的范围是-128~127,此时对于是否读取到结尾的判断-1,无法判断这个-1是字节值还是读取到了结尾。这里read()方法底层做了处理,使返回的数据都是整数,使用int类型来接收,避免了这种情况。
2.字节流复制非文本文件
1)读一个字节,写一个字节(边读边写)
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo06 {
public static void main(String[] args) throws IOException {
//将字符文件封装为对象,demo06source.png:143,355字节
File src = new File("D:\\javatest\\demo06source.png");
File tgt = new File("D:\\javatest\\demo06target.png");
//创建字节流FileInputStream对象,接受文件file
FileInputStream fis = new FileInputStream(src);
//创建字节流FileOutputStream对象,接受文件tgt
FileOutputStream fos = new FileOutputStream(tgt);
//读取文件
//1)每次读取一个字节
int count=0; //对于文件的字节数设置一个计数器
int n;
while ((n=fis.read())!=-1){
fos.write(n);
count++; //每读取一个字节,计数器+1
}
System.out.println("count="+count);
//关闭字节流
fis.close();
}
}
2)多个字节读取(缓冲数组),多个字节写入
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo06 {
public static void main(String[] args) throws IOException {
//将字符文件封装为对象,demo06source.png:143,355字节
File src = new File("D:\\javatest\\demo06source.png");
File tgt = new File("D:\\javatest\\demo06target.png");
//创建字节流FileInputStream对象,接受文件file
FileInputStream fis = new FileInputStream(src);
//创建字节流FileOutputStream对象,接受文件tgt
FileOutputStream fos = new FileOutputStream(tgt);
//读取文件
//2)缓冲数组读取多个字节
byte[] b = new byte[1024*2];//byte数组长度可以是1024的倍数
int len;
while ((len=fis.read(b))!=-1){
fos.write(b,0,len);
}
//关闭字节流
fis.close();
}
}
六、缓冲字节流:BufferedInputStream和BufferedOutputStream
1.访问原理
1)逐个字节读取,写入
2)缓冲数组读取,写入
从上面两种访问的方式,可以得出缓冲数组对于硬盘的访问次数远小于逐个读取,加快程序的读写速度,减少了对硬盘的损耗。
但是我们还可以引入缓冲流,使程序对硬盘的访问降低到1次。
FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了,缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。
3)缓冲流原理
相当于在FileInputStream和FileOutputStream外面再嵌套一层流
2.缓冲字节流BufferedInputStream和BufferedOutpuStream的用法
package com.rzd.no05io;
import java.io.*;
public class Demo07 {
public static void main(String[] args) throws IOException {
//1.将文件封装为对象
File src = new File("D:\\javatest\\demo06source.png");
File tgt = new File("D:\\javatest\\demo06target.png");
//2.创建访问字节流对象来接收文件对象
FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(tgt);
//3.嵌套缓冲字节流
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream bos = new BufferedOutputStream(fos);
//4.文件读取和写入
//对于字节流,使用byte数组接收
byte[] b = new byte[1024 * 6];
int len;
while ((len=bis.read(b))!=-1) {
bos.write(b,0,len);
//bos.flush(); //底层已经使用flushBuffer()刷新缓冲区,不用手动刷新
}
//5.关闭流(倒着关闭)
//FileInputStream节点流,BufferedInputStream处理流,关闭顺序为:先关闭处理流,再关闭节点流。
//可以直接关闭高级流(处理流),处理流关闭的时候,会调用节点流的关闭方法
bos.close();
bis.close();
/* fos.close();
fis.close();*/
}
}
3.对三种读取写入方式的速度的验证
按照原理,三种读取写入方式的速度应该为:逐个读取写入速度应该 < 缓冲数组读取的速度 < 缓冲流嵌套
可以利用System.currentTimeMillis()得到当前的系统时间来计算出
1)逐个读取写入
2)缓冲数组读取写入
3)缓冲流
时间过短,这里体现不出区别,换个大点的文件应该会有区别
七、缓冲字符流:BufferedReader和BufferedWriter
1.BufferedReader和BufferedWriter完成对文本文件的复制
1)逐个
import java.io.*;
public class Demo08 {
public static void main(String[] args) throws IOException {
/*demo04source.txt:
-FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
-但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
-缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//缓冲字符流嵌套
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
//文件读取、写入
//1)逐个
int n;
while ((n=br.read())!=-1){
bw.write(n);
}
bw.close();
br.close();
}
}
2)缓冲数组
import java.io.*;
public class Demo08 {
public static void main(String[] args) throws IOException {
/*demo04source.txt:
-FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
-但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
-缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//缓冲字符流嵌套
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
//文件读取、写入
//2)缓冲数组
char[] ch = new char[20];
int len;
while ((len=br.read(ch))!=-1){
bw.write(ch,0,len);
}
bw.close();
br.close();
}
}
3)逐行读取
BufferedReader缓冲流有readLine()方法
public class Demo08 {
public static void main(String[] args) throws IOException {
/*demo04source.txt:
-FileInputStream和FileOutputStream等流是与硬件(存储介质)进行的读取,所以速度较慢,当CPU需要使用数据时通过read()、read(byte[])读取数据时就要受到硬件IO的慢速度限制。
-但是CPU与内存发生的读写速度比硬件IO快10倍不止,所以引入了缓冲流:在内存中建立缓存区,先把存储介质中的数据读取到缓存区中。CPU需要数据时直接从缓冲区读就行了。
-缓冲区要足够大,在被读完后又触发fill()函数自动从存储介质的文件字节内容中读取字节存储到缓冲区数组。*/
File src = new File("D:\\javatest\\demo04source.txt");
File tgt = new File("D:\\javatest\\demo04target.txt");
FileReader fr = new FileReader(src);
FileWriter fw = new FileWriter(tgt);
//缓冲字符流嵌套
BufferedReader br = new BufferedReader(fr);
BufferedWriter bw = new BufferedWriter(fw);
//文件读取、写入
//3)BufferedReader缓冲流有readLine()方法,按行读取
String str ;
while ((str= br.readLine())!=null){
bw.write(str);
bw.newLine(); //这里必须加上新起一行的标志,否则读取到的内容不会换行
}
bw.close();
br.close();
}
}