节点流(文件流)
节点流
FileReader和FileWriter
字符流(cha[]数组)
FileReader读入数据的基本操作
过程
-
实例化File类的对象,指明要操作的文件
注意:
-
在@Test测试中的相对路径是相对于当前Module
-
在main函数的相对路径是相对于当前工程
-
-
提供具体的流
-
数据的读入过程
-
流的关闭操作
-
try-catch-finally异常处理
说明
- 一定要注意最后流的关闭
- read()的理解:返回读入的一个字符。如果达到文件末尾,返回-1
- 异常的处理:为了保证流资源一定可以执行关闭的操作,需要使用try-catch-finally来处理
- 读入的文件(hello.txt)一定要存在,否则会报FileNotFoundException异常
代码实现
@org.junit.Test
public void test1(){
FileReader fileReader = null;
try {
//1. 实例化File类的对象,指明要操作的文件
//注意:在@Test测试中的相对路径是相对于当前Module,在main函数的相对路径是相对于当前工程
File file = new File("hello.txt");//相对路径
//2. 提供具体的流
fileReader = new FileReader(file);
//3. 数据的读入过程
//read():返回读入的一个字符。如果达到文件末尾,返回-1
//方式一
// int data = fileReader.read();
// while(data != -1){
// System.out.print((char)data);
// data = fileReader.read();
// }
//方式二:语法上针对方式一的修改
int data;
while((data = fileReader.read()) != -1){
System.out.println((char)data);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 流的关闭操作
try {
//防止最开始提供流是出现异常导致这里是空指针,所以加一个判断
if(fileReader != null){
fileReader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果
此时的"hello.txt"文档中存储的内容是hello
使用read()的重载方法
- read():返回读入的一个字符。如果达到文件末尾,返回-1
- read(char[] cbuf):返回每次读入cbuf数组中的字符的个数。如果达到文件末尾,返回-1(常用)
- read(char cbuf[], int off, int len) (不常用)
read(char[] cbuf)的用法
-
创建一个char的数组cbuf
(举例假定该数组的长度为5)
char[] cbuf = new char[5];
-
创建len变量,存储read(char[] cbuf)的返回值
(注意:返回值即为每次读入cbuf数组中的字符的个数)
-
读取数据
- 写法一:循环遍历
for (int i = 0; i < len; i++) { System.out.print(cbuf[i]); }
- 写法二:char[]类型和String类型转换
String str = new String(cbuf,0,len); System.out.print(str);
-
流的关闭操作(不要忘记)
read(char[] cbuf)读取数据时的注意事项
-
写法一
for (int i = 0; i < len; i++) { System.out.print(cbuf[i]); }
其中for循环时,i一定要小于len(每次读入cbuf数组中的字符的个数)而不是cbuf.length
-
画图说明:
最后还剩下3个数据的时候:
-
如果for循环中的i小于cbuf.length(错误的写法)
最后的输出为:helloWorld123ld
(其中hello为第一次的结果,World为第二次的结果,123ld为第三次的结果)
而文件中的内容为helloWorld123,所以此时的写法是错误的
-
如果for循环中的i小于len(正确的写法)
最后的输出为:helloWorld123
(其中hello为第一次的结果,World为第二次的结果,123为第三次的结果)
-
-
-
写法二
String str = new String(cbuf,0,len); System.out.print(str);
其中利用了String(char[] value, int offset, int count)构造器,而不是String(char[] value)构造器
-
String(char[] value)构造器(错误的写法)
错误原因与写法一错误的方法相同 -
String(char[] value, int offset, int count)构造器(正确的写法)
读取char[]数组中角标0到角标len的内容,过程与写法一正确的方法过程类似
-
FileReader写出数据的基本操作
过程
- 实例化File类的对象,指明要操作的文件
- 提供具体的流
- 数据的写出过程
- 流的关闭操作
- try-catch-finally异常处理
说明
写出操作,对应的File可以不存在。
- 如果不存在,在写出的过程中,会自动创建此文件
- 如果存在这个文件
-
对原有文件的覆盖
流使用的构造器为
FileWriter(file, false)
或者是
FileWriter(file)
-
在原有文件的基础上追加内容(不会对原有文件进行覆盖)
流使用的构造器为
FileWriter(file, true)
-
代码实现
FileWriter fw1 = null;
FileWriter fw2 = null;
try {
//1. 提供File类的对象,指明写出到的文件
File file = new File("hi.txt");
//2. 提供FileWriter的对象,用于文件的写出
//覆盖
fw1 = new FileWriter(file,false);
//不覆盖
fw2 = new FileWriter(file,true);
//3. 写出的操作
fw1.write("I have a dream!\n");
fw2.write("123\n");
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 关闭流资源
if(fw1 != null)
try {
fw1.close();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(fw2 != null)
try {
fw2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果
最开始hi.txt文件中的内容为hello
运行代码后
使用FileWriter和FileReader实现文本文件的复制
过程
- 创建File类的对象,指明读入和写出的文件
- 创建输入流和输出流的对象
- 数据的读入和写入操作
- 关闭流资源
- try-catch-finally异常处理
说明
-
在读取文件文件时,选择read(char[] cbuf)的用法
-
在写入文件的时候,注意不要写成
fw.write(cbuf);
此时出现的错误和读取操作时写法一会出现的错误相同,不可以正确的读取文件中原本的内容
需要使用
fw.write(cbuf,0,len);
读取cbuf数组中角标为0的元素到角标为len的元素
-
在最后关闭流资源的时候,一定要注意两个流都要关闭,即使其中一个流在关闭的时候抛出异常另一个流也要关闭
有两种写法
- 写法一
finally { //4. 关闭流资源 if(fr != null) try { fr.close(); } catch (IOException e) { e.printStackTrace(); }finally { if(fw != null) try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } }
- 写法二
finally { //4. 关闭流资源 try { if(fr != null) fr.close(); } catch (IOException e) { e.printStackTrace(); } try { if(fw != null) fw.close(); } catch (IOException e) { e.printStackTrace(); } }
代码实现
public void test4(){
FileReader fr = null;
FileWriter fw = null;
try {
//1. 创建File类的对象,指明读入和写出的文件
File file1 = new File("hello.txt");
File file2 = new File("hi.txt");
//2. 创建输入流和输出流的对象
fr = new FileReader(file1);
fw = new FileWriter(file2,true);
//3. 数据的读入和写入操作
char[] cbuf = new char[5];
int len;//记录每次读入到cbuf数组中字符的个数
while((len = fr.read(cbuf)) != -1){
//每次写出len个字符
fw.write(cbuf,0,len);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
//4. 关闭流资源
try {
if(fr != null)
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fw != null)
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
运行结果
注意
字符流不能处理图片文件等字节数据!!!
FileInputStream和FileOutputStream
字节流(byte[])
使用FileInputStream和FileOutputStream实现文本文件的复制
过程
- 创建File类的对象,指明读入和写出的文件
- 创建输入流和输出流的对象
- 数据的读入和写入操作
- 关闭流资源
- try-catch-finally异常处理
代码实现
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcfile = new File("殷志源.png");
File destfile = new File("丸子.png");
fis = new FileInputStream(srcfile);
fos = new FileOutputStream(destfile);
byte[] buffer = new byte[5];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
运行结果
指定路径下文件的复制的方法
复制视频
public void copyFile(String srcPath, String destPath){
FileInputStream fis = null;
FileOutputStream fos = null;
try {
File srcfile = new File(srcPath);
File destfile = new File(destPath);
fis = new FileInputStream(srcfile);
fos = new FileOutputStream(destfile);
byte[] buffer = new byte[1024];
int len;
while((len = fis.read(buffer)) != -1){
fos.write(buffer,0,len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fis != null)
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
if(fos != null)
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
字节流和字符流使用的注意事项
- 对于文本文件(.txt, .java, .c, .cpp......),使用字符流来处理
- 对于非文本文件(.jpg, .mp3, .mp4, .avi, .doc, .ppt......),使用字节流来处理
- 如果只是想复制文本文件,也可以使用字节流(流在此时只是个搬运的作用)
- 非文本只可以用字节流操作