字符流是专门用来读写字符文件的流。字符流所处理的数据基本单元是字符,其输入输出操作都是在字符的基础上进行,Java语言中的字符采用Unicode字符编码,每个字符占2个字节空间,而文本文件有可能采用其它类型的编码,如GBK,UTF8编码方式,因此有时需要字符编码之间的转换。
字符流常见的操作接口类如下:
其中,Reader和Writer是两个抽象类不能直接实例,必须实例化它们的子类。而FileReader/FileWriter和BufferedReader/BufferedWriter分别是它们的子类。
1.FileReader和FileWriter实现文件读写
++Reader最常用的方法如下:++
public abstract int read() throws IOException;:抽象方法。从输入流读取单个字符,返回所读取的字符数据(字符数据可直接转换为int类型)。返回-1表示到了输入流的结束点。
public int read(char b[], int off, int len) throws IOException:从输入流中最多读取len个字符的数据,并将其存储在数组b中,放入数组b时,并不是从数组起点开始,而是从off位置开始,返回实际(实际长度可能小于len)读取的字符数。返回-1表示到了输入流的结束点。
public int read(char b[]) throws IOException:从输入流中最多读取b.length个字符的数据,并将其存储在数组b中,返回实际读取的字符数。相当于调用read(b, 0, b.length)。返回-1表示到了输入流的结束点。
++Writer最常用方法如下:++ public abstract void write(int b) throws IOException;:将指定的一个字符输出到输出流中,此处b表示一个字符。
public void write(char b[], int off, int len) throws IOException:将字符数组中从off位置开始,长度为len的字符输出到输出流中。
public void write(char b[]) throws IOException:将字符数组中的数据输出到指定输出流中。相当于调了write(b, 0, b.length)。
实例:使用字符流实现一个java源文件的复制每次读写一个字符并统计总用时多少毫秒。
public static void main(String[] args) {
Reader bin = null;
Writer bout = null;
File srcFile = new File("D:"+File.separator+"MyUtils.java");
File destFile = new File("E:"+File.separator+"MyUtils.java");
try{
bin = new FileReader(srcFile);
bout = new FileWriter(destFile);
long startTime = System.currentTimeMillis();
int ch=-1;
while((ch=bin.read())!=-1){ //每次读出一个字符
bout.write(ch); //写入一个字符
}
long endTime = System.currentTimeMillis();
System.out.println("总用时:"+(endTime - startTime)+"毫秒");
}catch(Exception ex){
ex.printStackTrace();
}finally{
try {
if(bin!=null) {
bin.close();
bin = null;
}
if(bout!=null) {
bout.close();
bout = null;
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果:
总用时:30毫秒
2.BufferedReader和BufferedWriter
BufferedReader和BufferedWriter 是带缓冲的输入和输出流可以大大提升读写效率。因为BufferedReader和BufferedWriter比Reader和Writer多出了readLine()和write(String)方法,可以按行读写。
注意:readLine()方法返回的是不带换行符号的一行字符串内容,因此在写入时必须手工拼上换行回车字符或者使用newLine()方法。
把上面的java源文件复制的例子改写为使用带缓冲的流实现。
public static void main(String[] args) {
BufferedReader bin = null;
BufferedWriter bout = null;
File srcFile = new File("D:"+File.separator+"MyUtils.java");
File destFile = new File("E:"+File.separator+"MyUtils.java");
try{
bin = new BufferedReader(new FileReader(srcFile));
bout = new BufferedWriter(new FileWriter(destFile));
long startTime = System.currentTimeMillis();
String s=null;
while((s=bin.readLine())!=null) { //一次读出一行字符串
bout.write(s+"\r\n"); //一次写入一行,后面手工拼上行号回车转义字符。
//或者使用bout.newLine();
}
long endTime = System.currentTimeMillis();
System.out.println("总用时:"+(endTime - startTime)+"毫秒");
}catch(Exception ex){
ex.printStackTrace();
}finally{
try {
if(bin!=null) {
bin.close();
bin = null;
}
if(bout!=null) {
bout.close();
bout = null;
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果:
总用时:3毫秒
3.InputStreamReader和OutputStreamWriter
InputStreamReader和OutputStreamWriter可以实现字节流转换为字符流。 例如:上面的java源文件复制的例子改写为使用字节流转字符流实现。
public static void main(String[] args) {
BufferedReader bin = null;
BufferedWriter bout = null;
File srcFile = new File("D:"+File.separator+"MyUtils.java");
File destFile = new File("E:"+File.separator+"MyUtils.java");
try{
//因为是字节流转字符流有可能出现中文乱码,必须指定正确的字符编码格式。
bin = new BufferedReader(new InputStreamReader(new FileInputStream(srcFile),"utf-8"));
bout = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(destFile),"utf-8"));
long startTime = System.currentTimeMillis();
String s=null;
while((s=bin.readLine())!=null) {
bout.write(s+"\r\n");
}
long endTime = System.currentTimeMillis();
System.out.println("总用时:"+(endTime - startTime)+"毫秒");
}catch(Exception ex){
ex.printStackTrace();
}finally{
try {
if(bin!=null) {
bin.close();
bin = null;
}
if(bout!=null) {
bout.close();
bout = null;
}
}catch(Exception e){
e.printStackTrace();
}
}
}
运行结果:
总用时:3毫秒