昨天给大家介绍了字节流是如何复制文件的,今天给大家介绍如何用字符流来完成文件的读入与复制。在介绍之前,先给大家说一说字节流与字符流各自针对那些文件以及关于字符流的输入输出的划分。
- 字节流与字符流各自针对的文件
1.字节流针对的文件有:文本文件(例如 txt / jpg图片 / word文档 ), 音频文件 ,视频文件,网络Socket等;
2.字节流针对的文件有:文本文件(例如 txt);
- 字符流的数据流向分类
Reader属于输入流
Writer属于输出流
在此处可能理解起来比较抽象,但是一定要时刻记住,方向都是以程序作为参考或者主体而言的,用程序读取一个文件,操作这个文件的类就是输入流,它输入到了程序中;用程序输出文件,操作此文件的类就是输出流,它是通过程序写出的。可能还是没说清楚,在此,我借用别人的一段话来充分说明IO流,也更加形象具体的回答一下第一个问题:
一、流的概念和作用
流:是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称和抽象。即数据在两设备间的传输成为流,流的本质是数据传输,根据数据传输特性将流抽象为各种类,方便更直观的进行数据操作。
二、流的分类
根据处理数据类型的不同分:字符流和字节流
根据数据流向不同分为:输入流和输出流
三、字符流和字节流
字符流的由来:因为数据编码的不同,而有了对字符进行高效操作的流对象。本质其实就是基于字节流读取时,去查了指定的码表。
字节流和字符流的区别:
(1)读写单位不同:字节流以字节(8bit)为单位,字符流以字符(16bit)为单位,根据码表映射字符。
(2)处理对象不同:字节流能处理所有类型的数据(如:图片、音乐、视频等媒体介质),而字符流只能处理字符类型的数据。
(3)字节流在操作的时候本身是不会用到缓冲区的,是文件本身的直接操作的;而字符流在操作的时候是会用到缓冲区的,是通过缓冲区来操作文件。
建议:当我们在处理媒体介质时,请选择字节流;当我们在处理字符介质时,请选择字符流;当我们不明确操作的介质的类型时,请选择字节流。
上述解释非常清晰明了的解释了IO流的基本问题。那接下来我们进入今天的内容:
- 使用字符流读取一个文件:
步骤如下:
1.创建一个文件的对象,用于将要读取的文件的位置与名称指明;
2.创建FileReader的对象,并将第一步创建的文件的对象作为参数传入它的构造方法;
3.读取操作;
4.关闭文件,至于为什么要关闭文件,我在前一篇文章中已经说明,此处不再赘述。
- 代码展示
package com.mec.about_readerAndWriter;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class FileReaderTest {
public static void main(String[] args) {
//1.创建一个文件的对象,将即将读取的文件的位置与名称指明;
File file = new File("Five.txt");
//2.创建FileReader这个节点流的对象,并将第一步创建的文件的对象传入它的构造方法的参数中
FileReader fr = null;
try {
fr = new FileReader(file);
//3.写出读入的程序。创建字符数组,存放由文件读取到的字符;
//定义len是为了记录保存在字符数组中的字符的长度;
char[] c = new char[20];
int len;
while((len = fr.read(c)) != -1) {
String string = new String(c, 0, len);
System.out.print(string);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.进行关闭文件操作,因为数据流不属于java内存资源,所以流不会被自动回收,要手动关闭
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
给大家看一看这个Five.txt文件的内容以及程序读取到之后在控制台输出的内容;
可以发现,上述操作与FileInputStream的操作很相似,大家可以对比学习。接下来给大家看看这个复制工作又是如何实现的。
- 使用字符流实现文件的复制操作
步骤如下:
1.创建两个文件的对象,一个用于指明即将读取的源文件的位置与名称,另一个则用于指明目的文件的位置与名称;
2.创建FileReader的对象,并将第一步创建的源文件的对象传入它的构造方法中;创建一个FileWriter的对象,并将第一步创建的目标文件的对象传入它的构造方法中;
3.进行读取,写入操作;
4.关闭文件,至于为什么要关闭文件,我在前一篇文章中已经说明,此处不再赘述。
- 代码展示
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class CopyFile {
public static void main(String[] args) {
//1.创建两个文件的对象,一个为源文件,另一个为目标文件;
//源文件必须存在,若不存在则会报错;目标文件可以不存在,若不存在会被创建;
//若存在会被覆盖
File src = new File("Five.txt");
File dest = new File("Six.txt");
//2.创建FileReader的对象,并将第一步创建的源文件的对象传入它的构造方法中;
//创建一个FileWriter的对象,并将第一步创建的目标文件的对象传入它的构造方法中;
FileReader fr = null;
FileWriter fw = null;
try {
fr = new FileReader(src);
fw = new FileWriter(dest);
//3. 进行读取;
char[] c = new char[20];
int len;
while((len = fr.read(c)) != -1) {
//3.写入操作;
fw.write(c, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//4.关闭文件
if(fr != null) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//4.关闭文件
if(fw != null) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
看完代码以后,我们来看一下工程目录的变化还有最终结果:
- 未执行代码前的目录:
- 执行完代码并刷新过后的工程目录:
- 执行结果,我将目标文件与源文件进行了对比,如下所示: