前面一章介绍了字节流的使用,提到了字节流在处理utf-8编码的中文可能会出现乱码的情况(其他编码的中文同样会出现乱码),所以Java针对这一情况提供了字符流。
但是字符流只能处理字符,不能用来处理 .jpg;.mp3;.mp4;.avi;.doc;.ppt等二进制文件,这些只能通过字节流来处理。所以对于纯文本的文件,强烈推荐使用字符输入输出流。
字符流的本质其实就是基于字节流在读取时去查了指定的码表。
1、字符输入流Reader
Reader是所有字符输入流的父类,定义了所有字符输入流都具有的共同特征。其内部提供的方法如下:
上图中重载的三个read()方法都是用来读数据的。
- int read():每次读取一个字符,并把它转换为 0~65535 的整数,然后返回读取到的字符。读到末尾返回-1。(为了提高 I/O 操作的效率,建议尽量使用下面两种read()方法)
- int read(char[] cbuf):将读取到的多个字符存储到 cbuf 中,然后返回读取的字符,读到末尾时返回-1。
- int read(char[] cbuf,int off,int len):将读取到的多个字符存储进字符数组 cbuf,从索引 off 开始,长度为len字符,返回结果为读取的字符数.
其中Reader的子类FileReader是专门用于读取文件中的数据,通过它将目标设备上的数据读入到程序。
FileReader读入文件举例(读取的hello.txt文件内容是:你好,我是中国人!):
package com.thr; import java.io.File; import java.io.FileReader; import java.io.IOException; /** * @author Administrator * @date 2020-02-23 * @desc 字符输入流FileReader */ public class FileReaderTest { public static void main(String[] args) { //定义输入流 FileReader fr =null; try { //1、创建文件对象 File file = new File("D:\IO\hello.txt"); //2、创建输入流对象 fr = new FileReader(file); //循环读取,读取到末尾返回-1 int len ;//记录每次读取的字节个数 while((len = fr.read())!=-1){ System.out.print((char)len); } } catch (IOException e) { e.printStackTrace(); } finally { //释放资源 try { fr.close(); } catch (IOException e) { e.printStackTrace(); } } } } 运行结果: 你好,我是中国人!
2、字符输出流Writer
Writer是所有字符输出流的父类,定义了所有字符输出流都具有的共同特征。其内部提供的方法如下:
上图中重载的五个write()方法都是用来写数据的。
- void write(int c):把一个字符写入到文件中。
- void write(char[] cbuf):把cbuf字符数组写入到文件中。
- void write(char[] cbuf,int off,int len):把部分字符数组写入到文件中,从 cbuf 数组的 off 索引开始,写入len个字符。
- void write(String str):把一个字符串写入到文件中。
- void write(String str,int off,int len):把部分字符串写入到文件中,从 字符串的 off 索引开始,写入len个字符。
其中Writer的子类FileWriter是门用于读出文件中的数据,通过它将数据从程序输出到目标设备。
FileWriter输出文件举例:
package com.thr; import java.io.File; import java.io.FileWriter; import java.io.IOException; /** * @author Administrator * @date 2020-02-23 * @desc 字符输出流FileWriter */ public class FileWriterTest { public static void main(String[] args) { //定义输出流 FileWriter fw =null; try { //1、创建文件对象 File file = new File("D:\IO\a.txt"); //2、创建输出流对象,保留原来的数据,在文件后面追加 fw = new FileWriter(file,true); //write():写出一个字符(utf-8编码) fw.write(20200223); fw.write(" ");//回车换行 //write(char[] buffer):把cbuf字符数组写入到文件中。 fw.write("我是中国人".toCharArray()); fw.write(" "); //write(char[] cbuf,int off,int len):把部分字符数组写入到文件中,从 cbuf 数组的 off 索引开始,写入len个字符。 fw.write("我是中国人".toCharArray(),1,4); fw.write(" "); //write(String str):把一个字符串写入到文件中。 fw.write("中国人"); fw.write(" "); //write(String str,int off,int len):把部分字符串写入到文件中,从 字符串的 off 索引开始,写入len个字符。 fw.write("你好,我是中国人 ",3,6); } catch (IOException e) { e.printStackTrace(); } finally { //释放资源 try { fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }
注意:如果字符输出流不调用close()方法关闭资源,数据只是保存到缓冲区,并不会保存到文件(这一点与FileOutputStream不同,即使它不调用close()方法依然会写入到文件中)。
这里就得介绍一下flush()这个方法。
flush()和close()方法的区别:
flush():将流中的缓冲区缓冲的数据刷新到目的地中,刷新后,流还可以继续使用。
close():关闭资源,但在关闭前会将缓冲区中的数据先刷新到目的地,否则丢失数据,然后在关闭流。流不可以使用。
而当我们亲自去使用flush()方法的时候会产生一个疑问,就算我们在close()之前不加flush()方法也不会影响文件的写出呀,那为什么还要用这个方法呢?先看一下下面的代码吧:
package com.thr; import java.io.FileWriter; import java.io.IOException; /** * @author Administrator * @date 2020-02-24 * @desc flush方法的使用 */ public class WriterFlushTest { public static void main(String[] args) { //定义输出流 FileWriter fw = null; //其实该步就是在明确数据要存放的目的地 try { fw=new FileWriter("D:\flush.txt"); fw.write("介");//调用write方法,将字符串写入到流中(使用write其实并没有将字符串直接写入到指定文件,而是存放在流中) fw.flush();//这一步才是将上一步write的所写的字符串冲刷到指定的文件(在指定的文件打开后有字符串存在了) fw.write("绍"); fw.flush(); fw.write("flush方法"); fw.flush(); fw.close();//close()是一定要做的(其实close方法中调用了flush方法) fw.write("CCC");//close后若再write,会提示IO异常Stream closed } catch (IOException e) { e.printStackTrace(); } } }
小声BB:我认为flush()方法可有可无,它就是将缓冲区的数据强制写入到文件中,因为在调用完write()方法后数据并没有写入到文件中,而是保存在流中,此时我们可以调用flush()方法,也可以在最后用close()方法来将数据写入文件,因为在close()的时候,也会进行一次flush的,因此close之前其实可以不用专门做flush的。但是在某些情况下,数据量较大的时候,在写的过程中,可以进行阶段性的flush。(话说我也不知道这样做会有什么好处……)
3、字符流拷贝文件
package com.thr; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; /** * @author Administrator * @date 2020-02-23 * @desc 拷贝文本文件 */ public class FileReaderWriterTest { public static void main(String[] args) { //定义输入流 FileReader fr =null; //定义输出流 FileWriter fw =null; try { //创建读入文件对象 File f1 = new File("D:\IO\hello.txt"); //创建读出文件对象 File f2 = new File("C:\a.txt"); fr = new FileReader(f1); fw = new FileWriter(f2); //循环读取,读取到末尾返回-1 char chars[] = new char[1024]; int len ;//记录每次读取的字节个数 while((len = fr.read(chars))!=-1){ fw.write(chars,0,len); } System.out.println("拷贝成功..."); } catch (IOException e) { e.printStackTrace(); } finally { //释放资源 try { fr.close(); fw.close(); } catch (IOException e) { e.printStackTrace(); } } } }