FileReader和FileWriter的源码相对简单,下面通过分析它们的源码以更好地进行理解这两个流

1. FileReader

FileReader实现了读取底层的字节数据并将其转换为字符数据的功能,转换时依赖的字符集为平台默认的字符集GBK(Windows平台)。

FileReader源码如下:

public class FileReader extends InputStreamReader {

    public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
} public FileReader(File file) throws FileNotFoundException {
super(new FileInputStream(file));
} public FileReader(FileDescriptor fd) {
super(new FileInputStream(fd));
}
}

  由源码可以看出,FileReader类继承自InputStreamReader类,它自己只提供了几个构造方法,它的构造方法中又通过super来调用父类构造器以构建流对象,它本身没有再提供其他的读取流数据的方法,全部继承它的直接父类InputStreamReader,而InputStreamReader又是继承自Reader类,因此FileReader和InputStreamReader一样,都能使用read()、read(char cbuf[])、read(char cbuf[], int off, int len)方法来读取流数据

  此外,由源码可知,FileReader的读取字符串的功能是通过转换流InputStreamReader类实现的:首先InputStreamReader包装了一个FileInputStream从文件读取字节数据,再将读取到的字节数据转换为字符。而FileReader继承了InputStreamReader,从而也获得了该功能。我们截取该类的其中一个构造方法的代码出来:

    public FileReader(String fileName) throws FileNotFoundException {
super(new FileInputStream(fileName));
}

  可以看到,在调用父类InputStreamReader的构造方法时,没有显式地指定解码所需的字符集,因此使用的是平台默认字符集来将读到的字节数据转换为字符。因此,FileReader去读取GBK编码的源文件数据时不会出现乱码,而在读取UTF-8等其他字符集编码的文件时就会粗现乱码了。

  从该流的API文档同样可以看出这点:FileReader是用来读取字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是适当的。若要自己指定这些值,可以先在 FileInputStream 上构造一个 InputStreamReader。 FileReader 用于读取字符流。要读取原始字节流,请考虑使用 FileInputStream。

综上,可知FileReader的本质其实还是字节流

FileReader类使用示例代码:

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException; public class FileReaderTest {
public static void main(String[] args) { System.out.println("【从GBK文件读取到的内容】:");
test1();
System.out.println("\n\n【从UTF-8文件读取到的内容】:");
test2(); } ////////////////////////////////////////////////////////////
/**
* 使用FileReader从编码为GBK的源文件1.txt中读取数据,能正确读取
*/
private static void test1() {
FileReader fr = null; try {
fr = new FileReader("./src/res/1.txt"); int value = 0; while(-1 != (value = fr.read())) { //使用read()方法读取
System.out.print((char)value);
} } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} ////////////////////////////////////////////////////////////
/**
* 使用FileReader从编码为utf-8的源文件2.txt中读取数据,将出现乱码
*/
private static void test2() {
FileReader fr = null; try {
fr = new FileReader("./src/res/2.txt"); int len = 0;
char[] buf = new char[1024]; //注意这里是字符数组!! while(-1 != (len = fr.read(buf))) { //使用read(char cbuf[])方法读取
System.out.println(new String(buf));
} } catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != fr) {
try {
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

代码运行效果:

【从GBK文件读取到的内容】:
hello java hello hello 中国 【从UTF-8文件读取到的内容】:
hello java hello hello 涓浗

  可见,若是使用FileReader从UTF-8文件中读取数据,将会出现乱码,原因在上面也说了,是因为FileReader的底层转换流InputStreamReader在将字节数据转换为字符数据时,使用的是平台默认的字符集GBK,与源文件的不一致,由此导致了乱码。

2. FileWriter

  FileWriter实现了将字符数据转换为字节数据的功能。它所依赖的字符集也是平台默认的GBK 。

  API文档中关于FileWriter有如下描述:用来写入字符文件的便捷类。此类的构造方法假定默认字符编码和默认字节缓冲区大小都是可接受的。若想要自己指定这些值,可以先在 FileOutputStream 上构造一个 OutputStreamWriter。

FileWriter源码如下:

public class FileWriter extends OutputStreamWriter {

    public FileWriter(String fileName) throws IOException {
super(new FileOutputStream(fileName));
} public FileWriter(String fileName, boolean append) throws IOException {
super(new FileOutputStream(fileName, append));
} public FileWriter(File file) throws IOException {
super(new FileOutputStream(file));
} public FileWriter(File file, boolean append) throws IOException {
super(new FileOutputStream(file, append));
} public FileWriter(FileDescriptor fd) {
super(new FileOutputStream(fd));
} }

  由FileWriter的源码可以看到,该类的直接父类是转换流OutputStreamWriter,它跟FileReader简直一模一样——自己只提供了几个构造方法,并在它的构造方法中又通过super来调用父类构造器以构建流对象,它本身没有再提供其他的写出流数据的方法,全部继承它的直接父类OutputStreamWriter,而OutputStreamWriter又是继承自Writer类,因此FileWriter和OutputStreamWriter一样,都能使用write(int c)、write(char cbuf[])、write(char cbuf[], int off, int len)、write(String str)、write(String str, int off, int len)方法来写入流数据

FileWriter流使用示例代码:

import java.io.FileWriter;
import java.io.IOException; public class FileWriterTest {
public static void main(String[] args) {
FileWriter fw = null; try {
fw = new FileWriter("./src/res/3.txt"); String str1 = "hello java";
String str2 = "中国"; char[] array = str1.toCharArray();//将字符串转换为字符数组 fw.write(str1, 0, 5); //写入:hello
fw.write(str2); //写入:中国
fw.write(array); //写入:hello java
fw.write(array, 6, 4); //写入:java } catch (IOException e) {
e.printStackTrace();
} finally {
if(null != fw) {
try {
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

代码运行效果:

本次示例中,是将数据写入GBK编码的目标文件中,倘若目标是UTF-8或者其他编码,则写入的数据中文会发生乱码,如下所示:

使用FileReader和FileWriter在两个文件之间相互拷贝文件的操作跟前边的示例差不多,这里不再写了。

3. 小结

FileInputStream、FileOutputStream、FileReader和FileWriter都是跟磁盘文件有关的字节流或字符流但凡需要跟磁盘文件进行I/O操作的,必将使用到它们中的其中一个。需要根据读取的是字节流还是字符流来进行相应的选择。

J04-Java IO流总结四 《 FileReader和FileWriter 》的更多相关文章

  1. Java IO(十七)FIleReader 和 FileWriter

    Java IO(十七)FIleReader 和 FileWriter 一.介绍 FIleReader 和 FileWriter 是读写字符文件的便利类,分别继承于 InputStreamReader ...

  2. java io系列22之 FileReader和FileWriter

    FileReader 是用于读取字符流的类,它继承于InputStreamReader.要读取原始字节流,请考虑使用 FileInputStream.FileWriter 是用于写入字符流的类,它继承 ...

  3. java IO流 (四) 缓冲流的使用

    1.缓冲流涉及到的类: * BufferedInputStream* BufferedOutputStream* BufferedReader* BufferedWriter 2.作用:作用:提供流的 ...

  4. IO流8 --- 使用FileReader和FileWriter实现文本文件的复制 --- 技术搬运工(尚硅谷)

    @Test public void test4(){ FileReader fr = null; FileWriter fw = null; try { fr = new FileReader(&qu ...

  5. Java IO流学习总结四:缓冲流-BufferedReader、BufferedWriter

    在上一篇文章中Java IO流学习总结三:缓冲流-BufferedInputStream.BufferedOutputStream介绍了缓冲流中的字节流,而这一篇着重介绍缓冲流中字符流Buffered ...

  6. Java IO流题库

    一.    填空题 Java IO流可以分为   节点流   和处理流两大类,其中前者处于IO操作的第一线,所有操作必须通过他们进行. 输入流的唯一目的是提供通往数据的通道,程序可以通过这个通道读取数 ...

  7. JAVA.IO流学习笔记

    一.java.io 的描述 通过数据流.序列化和文件系统提供系统输入和输出.IO流用来处理设备之间的数据传输 二.流 流是一个很形象的概念,当程序需要读取数据的时候,就会开启一个通向数据源的流,这个数 ...

  8. 转:Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  9. Java IO流简介

    Java中的流是什么? java中的流是一个抽象的概念,在java的程序中需要把文件从一个设备传输到另一个设备上,这个设备可以是内存,程序,文件,网络.把在这些之间传输的叫做流.官方的解释:流是一组有 ...

  10. Java IO 流总结篇

    1. 写在前面的话 I/O ,I 是 Input (输入)的缩写,O是Output (输出) 的缩写,众所周知,人与人之间想要沟通交流,就需要讲彼此都能听懂的语言,比如大家都统一说英语. 人类如果想和 ...

随机推荐

  1. Nginx upstream的5种权重分配方式(转)

    出处:http://www.cnblogs.com/funsion/p/4003499.html?utm_source=tuicool 1.轮询(默认) 每个请求按时间顺序逐一分配到不同的后端服务器, ...

  2. 解决Jedis链接报超时异常和connection reset异常的方法

    一.链接池配置 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" ...

  3. Java基础知识学习笔记(一)

    理解面向对象: Java纯粹的面向对象的程序设计语言,主要表现为Java完全支持面向对象的三个基本特征:继承.封装.多态. Java程序的最小单位是类,类代表客观世界中具有某种特征的一类事物,这些类可 ...

  4. win10 新增删除文件不刷新

    实际上是桌面图标缓存出问题,以下是一个简单动作即可解决问题. 按Win+R键打开“运行”窗口,输入如下命令后按回车键执行: ie4uinit -show 立竿见影,效果同360,魔方等工具软件,可参考 ...

  5. C语言学生管理系统源码分享

    大家好 我就是如假包换的...陈玲 自从运营了C语言程序设计微信公众号 很多粉丝都给我备注 ...奇葩 实在是不敢当 也被人开始叫玲玲姐 我知道 很多人都想看我出境 我本人也有 年多的舞台演讲训练 实 ...

  6. HDU 1847 Good Luck in CET-4 Everybody! (博弈)

    题意:不用说了吧,都是中文的. 析:虽说这是一个博弈的题,但是也很简单的,在说这个题目前我们先说一下巴什博弈定理. 巴什博弈定理:一堆物品有n个,有两个人(两个人足够聪明)轮流取,规定每次至少取一个, ...

  7. 关于this对象

    1.在全局函数中this指的是window 2.当函数被当做方法调用时,this等于那个对象 3.匿名函数具有全局性,只要是匿名函数,this指向window 实例1: var name = 'the ...

  8. TCP协议理解

    一.前言: TCP协议和UDP协议是网络编程里最重要的协议,很多新出的技术.新出的协议本质上都是基于这两个协议的,其中又以TCP协议居多:比如HTTP协议就是基于TCP协议的,应用程序和数据库交互也是 ...

  9. sql笔试练习

    转:http://www.360doc.com/content/16/0919/17/14804661_592046675.shtml 本文是在Cat Qi的参考原帖的基础之上经本人一题一题练习后编辑 ...

  10. (KMP 暴力)Corporate Identity -- hdu -- 2328

    http://acm.hdu.edu.cn/showproblem.php?pid=2328 Corporate Identity Time Limit: 9000/3000 MS (Java/Oth ...