Apache commons io 效率之尝试与瞎写

         我们使用Apache commons io,主要是为了提升各种效率。比如开发的效率,读取文件的效率,输出的效率等。输入、输入效率上的提升,是这个工具安身立命的本钱,是本;而开发效率的提升,能够让我们开发、项目相关人员获取实在的效益,是叶。

         我们先说叶,再说本,对或者错,都是我的一家之言,仅供参考。

 

●在input中,最值得关注的方法之一是AutoCloseInputStream

这个输入流是一个底层输入流的代理,它能够在数据源的内容被完全读取到输入流后,后者当用户调用close()方法时,立即关闭底层的输入流。释放底层的资源(例如文件的句柄)。这个类的好处就是避免我们在代码中忘记关闭底层的输入流而造成文件处于一直打开的状态。

我们知道对于某些文件,只允许由一个进程打开。如果我们使用后忘记关闭那么该文件将处于一直“打开”的状态,其它进程无法读写。例如下面的例子:

 InputStream ins = new FileInputStream(newFile("D:\\ffm83\\ffm83.txt"));
里面的FileInputStream(FILE)在打开后不能被显式关闭,这将导致可能出现的问题。如果我们使用了AutoCloseInputStream,那么当数据读取完毕后,底层的输入流会被自动关闭,迅速地释放资源。
AutoCloseInputStream ins =newAutoCloseInputStream((new FileInputStream(newFile("D:\\ffm83\\ffm83.txt"))));

示例代码:

packagetest.ffm83.commons.io;

 

importjava.io.File;

importjava.io.FileInputStream;

importjava.io.FileWriter;

importjava.io.IOException;

importjava.io.Writer;

importorg.apache.commons.io.IOUtils;

importorg.apache.commons.io.input.AutoCloseInputStream;

importorg.apache.commons.lang.StringUtils;

/**

 * commonsio 的一些简单基本用法

 * @author范芳铭

 */

public classIOAutoCloseUsage {

 

    publicstatic void main(String[] args) throws Exception {

        getInputCopyToWrite();

    }

   

    /**

     * 输入流复制到输出流,利用AutoCloseInputStream

     * @author 范芳铭

     */

    privatestatic void getInputCopyToWrite() throws Exception {   

        AutoCloseInputStreamins =new AutoCloseInputStream((new FileInputStream(newFile("D:\\ffm83\\ffm83.txt"))));

        Writerwrite = new FileWriter("D:\\ffm83\\write.txt");

        try{

            IOUtils.copy(ins,write);

            System.out.println(StringUtils.center("输入流复制到输出流成功",50, "-"));

        }catch(IOException e){

            System.out.println(StringUtils.center("输入流复制到输出流失败",50, "-"));

            e.printStackTrace();

        }  

        write.close();

        //ins.close(); 

    }

}

 

●在output中,最重要的方法是ByteArrayOutputStream,FileWriterWithEncoding,LockableFileWriter

ByteArrayOutputStream 方法提升了输入输出的效率;

FileWriterWithEncoding 提供了特殊功能简化了效率;

LockableFileWriter 提供了特殊的功能;

 

为了查看Apache提供的ByteArrayOutputStream是怎么提供效率的,我们写个程序来看看。为了让测试有一定的客观性,我们利用http://blog.csdn.net/ffm83/article/details/41848149博客的页面的源代码,保存到本地进行。这个页面的源代码保存的文件对应的就是D:\\ffm83\\ffmBlog.txt。

测试用代码如下:

packagetest.ffm83.commons.io;

 

importjava.io.ByteArrayOutputStream;

importjava.io.File;

importjava.io.FileInputStream;

importorg.apache.commons.io.input.AutoCloseInputStream;

importorg.apache.commons.lang.time.StopWatch;

 

/**

 * commons io 的ByteArrayOutputStream方法和java自带的ByteArrayOutputStream效率比较。

 * @author 范芳铭

 */

publicclass ByteArrayOutputStreamTest {

         public final static int BUFFER_SIZE =4096;

        

         public static void main(String[] args)throws Exception {

                   runTestApacheMethod(100000,"热身APACH方法");  //热身下

                   runTestApacheMethod(500000,"执行APACHE方法"); //正式开跑

                  

                   runTestJavaMethod(100000,"热身JAVA自带"); //热身下

                   runTestJavaMethod(500000,"执行JAVA自带"); //正式开跑

         }

        

         /**

          * 测试用的主运行方法

          * @author 范芳铭

          */

         private static voidrunTestJavaMethod(int iterations,String name) throws Exception{

                   StopWatch sw = newStopWatch();

                   sw.start();

                   for(int i = 0 ; i <iterations ;  i ++){

                            //在这里调用需要运行的方法

                            runJavaByteArrayOutputStream();

                   }

                   sw.stop();

                   System.out.println(name +",累计花费的时间:" + sw.getTime() );

         }

        

         private static voidrunTestApacheMethod(int iterations,String name) throws Exception{

                   StopWatch sw = newStopWatch();

                   sw.start();

                   for(int i = 0 ; i <iterations ;  i ++){

                            //在这里调用需要运行的方法

                            runApacheByteArrayOutputStream();

                   }

                   sw.stop();

                   System.out.println(name +",累计花费的时间:" + sw.getTime());

         }

        

         /**

          * 看java自带的ByteArrayOutputStream效率

          * @author 范芳铭

          */

         private static voidrunJavaByteArrayOutputStream() throws Exception {      

                   AutoCloseInputStream ins =newAutoCloseInputStream((new FileInputStream(

                                     newFile("D:\\ffm83\\ffmBlog.txt"))));

                   ByteArrayOutputStreambouts=new ByteArrayOutputStream();

                   byte[] data = newbyte[BUFFER_SIZE];

                   int count = -1;

                   while((count =ins.read(data,0,BUFFER_SIZE)) != -1)

                             bouts.write(data, 0, count);

                  

                   bouts.close();      

         }

        

         /**

          * 看java自带的ByteArrayOutputStream效率

          * @author 范芳铭

          */

         private static voidrunApacheByteArrayOutputStream() throws Exception { 

                   AutoCloseInputStream ins =newAutoCloseInputStream((new FileInputStream(

                                     newFile("D:\\ffm83\\ffm83.txt"))));

                   org.apache.commons.io.output.ByteArrayOutputStreambouts =

                                     neworg.apache.commons.io.output.ByteArrayOutputStream();

                   byte[] data = newbyte[BUFFER_SIZE];

                   int count = -1;

                   while((count = ins.read(data,0,BUFFER_SIZE))!= -1)

                             bouts.write(data, 0, count);

                   bouts.close();      

         }

}

运行结果如下:

热身APACH方法,累计花费的时间:9184

执行APACHE方法,累计花费的时间:43893

热身JAVA自带,累计花费的时间:17144

执行JAVA自带,累计花费的时间:85052

 

时间效率提升不到50%,难道我眼镜戴错了吗?

不过蚊子腿再细也是肉,虽然提升不多,好歹也是进步。换个思路再试试吧。

    /**

     * 看java自带的ByteArrayOutputStream效率

     * @author 范芳铭

     */

    privatestatic void runJavaByteArrayOutputStream() throwsException {  

        AutoCloseInputStreamins =new AutoCloseInputStream((new FileInputStream(

                newFile("D:\\ffm83\\ffmBlog.txt"))));

        ByteArrayOutputStreambouts=new ByteArrayOutputStream();

        byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count);

       

        bouts.close(); 

    }

这代码里有几个主要方法,一个是AutoCloseInputStream读取流文件,然后才是ByteArrayOutputStream,不知道是否是两个互相有影响,那么把这个方法移开试试看吧。

调整后的代码如下:

package test.ffm83.commons.io;

 

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileInputStream;

importorg.apache.commons.io.input.AutoCloseInputStream;

import org.apache.commons.lang.time.StopWatch;

 

/**

 * commonsio 的ByteArrayOutputStream方法和java自带的ByteArrayOutputStream效率比较。

 * @author范芳铭

 */

public class ByteArrayOutputStreamTest {

    publicfinal static int BUFFER_SIZE = 4096;

   

    publicstatic void main(String[] args) throws Exception {

        AutoCloseInputStreamins =new AutoCloseInputStream((new FileInputStream(

                newFile("D:\\ffm83\\ffmBlog.txt"))));

       

        runTestApacheMethod(100000,"热身APACH方法",ins);  //热身下

        runTestApacheMethod(500000,"执行APACHE方法",ins);//正式开跑

       

        runTestJavaMethod(100000,"热身JAVA自带",ins);//热身下

        runTestJavaMethod(500000,"执行JAVA自带",ins);//正式开跑

    }

   

    /**

     * 测试用的主运行方法

     * @author 范芳铭

     */

    privatestatic void runTestJavaMethod(int iterations,String name,

            AutoCloseInputStreamins) throws Exception{

        StopWatchsw = new StopWatch();

        sw.start();

        for(inti = 0 ; i < iterations ;  i ++){

            //在这里调用需要运行的方法

            runJavaByteArrayOutputStream(ins);

        }

        sw.stop();

        System.out.println(name+ ",累计花费的时间:" + sw.getTime() );

    }

   

    privatestatic void runTestApacheMethod(int iterations,String name,

            AutoCloseInputStreamins) throws Exception{

        StopWatchsw = new StopWatch();

        sw.start();

        for(inti = 0 ; i < iterations ;  i ++){

            //在这里调用需要运行的方法

            runApacheByteArrayOutputStream(ins);

        }

        sw.stop();

        System.out.println(name+ ",累计花费的时间:" + sw.getTime());

    }

   

    /**

     * 看java自带的ByteArrayOutputStream效率

     * @author 范芳铭

     */

    privatestatic void runJavaByteArrayOutputStream(AutoCloseInputStream ins) throwsException {  

       

        ByteArrayOutputStreambouts=new ByteArrayOutputStream();

        byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count);

       

        bouts.close(); 

    }

   

        /**

     * 看apache的ByteArrayOutputStream效率

     * @author 范芳铭

     */ privatestatic void runApacheByteArrayOutputStream(AutoCloseInputStream ins) throwsException {

        org.apache.commons.io.output.ByteArrayOutputStreambouts =

                neworg.apache.commons.io.output.ByteArrayOutputStream();

        byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count);

        //bouts.write(ins);

        bouts.close(); 

    }

}

运行结果如下:

热身APACH方法,累计花费的时间:128

执行APACHE方法,累计花费的时间:530

热身JAVA自带,累计花费的时间:85

执行JAVA自带,累计花费的时间:434

 

这个,这个出人意料,apache commons 的方法居然比java原生态的居然要慢50%。查看apachecommons io中关于ByteArrayOutputStream的部分,相比于JDK自带的方法,这个类多了一个write(InputStream in)的方法。

把这段代码调整下:

    privatestatic void runApacheByteArrayOutputStream(AutoCloseInputStreamins) throws Exception {

        org.apache.commons.io.output.ByteArrayOutputStreambouts =

                neworg.apache.commons.io.output.ByteArrayOutputStream();

/*      byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count); */

        bouts.write(ins);

        bouts.close(); 

    }

运行结果如下:

热身APACH方法,累计花费的时间:43

执行APACHE方法,累计花费的时间:146

热身JAVA自带,累计花费的时间:82

执行JAVA自带,累计花费的时间:354

 

这一次,apache commons 的方法比java原生态的居然要快50%以上。使用新的类,那么就要尽量用它配套的方法,否则有可能得到错误甚至相反的结果。

 

我们这个应用,用到的方法很少,因此可以进一步研究:

ByteArrayOutputStream() 
          Creates a new byte array output stream.

ByteArrayOutputStream(int size) 
          Creates a new byte array output stream, with a buffer capacity of the specified size, in bytes.

有一个是有参数的,一个是没有参数的,我们刚才测试用的是没有参数的。我们在各种buff中可能有了解,如果把buff的值扩大,一般效率会提升的,试验是检验真理的最高标准,我们动手试一下。

代码做一下调整:

    /**

     * 看apache的ByteArrayOutputStream效率

     * @author 范芳铭

     */

    privatestatic void runApacheByteArrayOutputStream(AutoCloseInputStreamins) throws Exception {

        org.apache.commons.io.output.ByteArrayOutputStreambouts =

                neworg.apache.commons.io.output.ByteArrayOutputStream(40960);

/*      byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count); */

        bouts.write(ins);

        bouts.close(); 

    }

运行结果如下:

热身APACH方法,size40960,累计花费的时间:668

执行APACHE方法,size40960,累计花费的时间:3702

热身JAVA自带,累计花费的时间:74

执行JAVA自带,累计花费的时间:379

 

代码继续调整下:

    /**

     * 看apache的ByteArrayOutputStream效率

     * @author 范芳铭

     */

    privatestatic void runApacheByteArrayOutputStream(AutoCloseInputStream ins)throws Exception {

        org.apache.commons.io.output.ByteArrayOutputStreambouts =

                neworg.apache.commons.io.output.ByteArrayOutputStream(4);

/*      byte[]data = new byte[BUFFER_SIZE];

        intcount = -1;

        while((count= ins.read(data,0,BUFFER_SIZE)) != -1)

             bouts.write(data, 0, count); */

        bouts.write(ins);

        bouts.close(); 

    }

运行结果如下:

热身APACH方法,size4,累计花费的时间:22

执行APACHE方法,size4,累计花费的时间:73

热身JAVA自带,累计花费的时间:79

执行JAVA自带,累计花费的时间:355

 

尝试了这么多,总结一下:

l   使用新的类,那么就要尽量用它配套的方法,否则有可能得到错误甚至相反的结果;

l   参数不要去想当然,要根据实际情况去调整,如果对效率有特殊要求,必要的测试是不可缺少的;

 

 

FileWriterWithEncoding

从这个类的名称已经可以很清楚的知道它的作用了。在JDK自带的FileWriter中,是无法设置encoding的,这个类允许我们采用默认或者指定的encoding,以字符的形式写到文件。为什么这个类可以改变字符嗯?
原理很简单:无非使用了OutputStreamWriter。而且这个类并不是继承与FileWriter,而是直接继承于Writer。

 

●LockableFileWriter
用“文件锁”而非“对象锁”来限制多线程环境下的写动作。这个类采用在JDK默认的系统临时目录下写文件:java.io.tmpdir属性。而且允许我们设置encoding。

如果多线程需要读写同一个文件,那么可以通过本方法对文件进行加锁操作。

   

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。