Fork 2me on GitHub

FileWriter与BufferedWriter的适用场景

IO这块,各种Writer,Reader,让人眼晕

而在网上基本找不到在什么时候用哪个类,并且网上的IO demo 很多用法都是错的

在这简单的分析一下FileWriter与BufferedWriter

一、两个类的继承关系

FileWriter BufferedWriter

java.lang.Object

  𠃊 java.io.Writer

    𠃊 java.io.OutputStreamWriter

      𠃊 java.io.FileWriter

java.lang.Object

  𠃊 java.io.Writer

    𠃊 java.io.BufferedWriter

 

 

 

 

 

 

由继承关系简单的来看,FileWriter是非常有意思的,它继承了OutputStreamWriter,这意味着它的写入是由FileOutputStream实现的,

这与我在前一篇《字节流与字符流的一些个人看法》中写到的内容相符合:字节用来与文件打交道,而字符用来和人打交道。

简单的说,FileWriter它的存在价值就在于方便人们写入字符串(即人能看懂的东西),它的内部依然是由FileOutputStream实现。

而BufferedWriter直接继承于java.io.Writer,看它的构造函数与用法,明显使用了装饰设计模式

这意味着我们要使用它,就必须给他一个Writer才可以,在该文章中我们假设给定的Writer就是FileWriter。

 二、两个类的用法

 FileWriter  BufferedWriter
FileWriter fw = null;
try {
    fw = new FileWriter("c:/123456");
    fw.write("0123456789");
    fw.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally{
    //关闭FileWriter
    try {
    if(null != fw)
        fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

FileWriter fw = null;
BufferedWriter bw = null;
try {
    fw = new FileWriter("c:/123456");
    //装饰模式,bw为包装对象,fw为真实对象
    bw = new BufferedWriter(fw);
    bw.write("0123456789");
    bw.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally{
    //关闭BufferedWriter
    try {
        if(null != bw)
            bw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    //关闭FileWriter
    try {
        if(null != fw)
            fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

从两个类的用法上来看,一个直接创建了FileWriter对象,写入数据

另一个,创建了FileWriter对象后,又创建了BufferedWriter对象,利用装饰模式操作BufferedWriter对象写入数据

同样的功能,两种方式都能实现,那么BufferedWriter存在的意义是什么?

三、BufferedWriter存在的意义

在网上能找到的答案基本都是: BufferedWriter输出时有缓冲区。

但是FileWriter也有啊,他们区别仅仅是FileWriter缓冲区大小为1024,而BufferedWriter默认缓冲区大小为8192,并且可以自己设置

为了测试,下面的程序分别用FileWriter、和BufferedWriter输出10M的字符串

FileWriter BufferedWriter
 
//接近10M的字符串
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10000000; i++){
    sb.append("0123456789");
}

FileWriter fw = null;
try {
    fw = new FileWriter("c:/123456");
    fw.write(sb.toString());
    fw.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally{
    //关闭FileWriter
    try {
        if(null != fw)
            fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

 
//接近10M的字符串
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10000000; i++){
    sb.append("0123456789");
}

FileWriter fw = null;
BufferedWriter bw = null;
try {
    fw = new FileWriter("c:/123456");
    //装饰模式,bw为包装对象,fw为真实对象
    bw = new BufferedWriter(fw);
    bw.write(sb.toString());
    bw.flush();
} catch (IOException e) {
    e.printStackTrace();
} finally{
    //关闭BufferedWriter
    try {
        if(null != bw)
            bw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    //关闭FileWriter
    try {
        if(null != fw)
            fw.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

 

714ms 600ms

从结果来看,他们的效率是有区别的,但区别并没到悬殊的地步

所以,这并不是他们区别的关键,在阅读两个类的源码后,我认为他们的最关键的区别在于:

FileWriter每次调用write()方法,就会调用一次OutputStreamWriter中的write()方法

而BufferedWriter只有在缓冲区满了才会调用OutputStreamWriter中的write()方法

为此我重写了FileWriter与OutputStreamWriter两个类,用来测试调用10000000次write()方法时OutputStreamWriter的write()方法执行次数

测试结果如下:

  FileWriter BufferedWriter
OutputStreamWrite的write()方法执行次数 10000000次 12207次
时间 1387ms 718ms

四、总结

BufferedWriter的执行速度确实要比FileWriter快,这方面的原因我还没找到。

但BufferedWriter在执行过程中增加了一层缓冲区,用来避免频繁执行OutputStreamWriter的write()方法

所以:

在一次性写入字符串到文件时可以直接调用FileWriter,在效率上影响不大

需多次写入字符串到文件时应调用BufferedWriter,可以避免频繁执行OutputStreamWriter的write()方法

五、题外话

网上能找到的区别大致上是

1、BufferedWriter输出时有缓冲区

2、BufferedWriter的write方法可以避免频繁的硬盘读写

这两种说法其实都是错误的

第一种:无论FileWriter还是BufferedWriter都有缓冲区,而缓冲区的大小1024已经足够

第二种:BufferedWriter的write方法无法实现避免频繁的硬盘读写,因为OutputStreamWriter的write()方法调用了StreamEncoder的write方法,而它的实现有缓冲区的存在,

    所以只有在缓冲区满的情况下才会写入硬盘,因此FileWriter还是BufferedWriter的硬盘读写应该一致。

    而真正的区别在于OutputStreamWriter的write()方法的调用次数

网上的东西很多是错的,包括这一篇,也不一定正确。

posted @ 2015-05-26 09:55  笑尽云荒  阅读(1590)  评论(1编辑  收藏  举报