几种Java读写数据的流性能对比

  近来,在做服务器后台处理数据的时候,需要用到Java自带的几种流对数据进行读写,初始时没怎么在意,就随便用了一个,结果发现性能上并不尽如人意。于是对几种常用的流做了个小小的性能测试。测试代码如下:

  1     public static int FileOutputStreamTime = 0;
  2     public static int BufferedOutputStreamTime = 0;
  3     public static int FileWriterTime = 0;
  4     public static int FileInputStreamTime = 0;
  5     public static int BufferedInputStreamTime = 0;
  6     public static int FileReaderTime = 0;
  7     
  8     public static void write(String filePath, String content){
  9         FileOutputStream out = null;
 10         FileOutputStream outStr = null;
 11         BufferedOutputStream buf = null;
 12         FileWriter fw = null;
 13         File f = new File(filePath);
 14         
 15         try {
 16             //Test FileOutputStream
 17             long begin1 = System.currentTimeMillis();            
 18             out = new FileOutputStream(f);
 19             out.write(content.getBytes());
 20             out.close();
 21             long end1 = System.currentTimeMillis();
 22             FileOutputStreamTime += end1 - begin1;
 23 
 24             //Test BufferedOutputStream
 25             long begin2 = System.currentTimeMillis();
 26             outStr = new FileOutputStream(f);
 27             buf = new BufferedOutputStream(outStr);
 28             buf.write(content.getBytes());
 29             buf.flush();
 30             buf.close();
 31             long end2 = System.currentTimeMillis();
 32             BufferedOutputStreamTime += end2 - begin2;
 33 
 34             //Test FileWriter
 35             long begin3 = System.currentTimeMillis();
 36             // the second parameter "true",Whether or not a file will be covered
 37             // or appended.
 38             fw = new FileWriter(f);
 39             // fw = new FileWriter("d:/test/testwrite/add2.txt",true);
 40             fw.write(content);
 41             fw.close();
 42             long end3 = System.currentTimeMillis();
 43             FileWriterTime += end3 - begin3;
 44         } catch (Exception e) {
 45             e.printStackTrace();
 46         } finally {
 47             try {
 48                 fw.close();
 49                 buf.close();
 50                 outStr.close();
 51                 out.close();
 52             } catch (Exception e) {
 53                 e.printStackTrace();
 54             }
 55         }
 56     }
 57     
 58     public static void read(String filePath){
 59         FileInputStream in = null;
 60         BufferedInputStream buf = null;
 61         FileReader reader = null;
 62         BufferedReader br = null;
 63         StringBuffer sb = new StringBuffer();
 64         
 65         try {
 66             //Test FileInputStream
 67             long begin1 = System.currentTimeMillis();
 68             File f = new File(filePath);
 69             in = new FileInputStream(f);
 70             int len1 = 512;
 71             byte[] bytes1 = new byte[len1];
 72             
 73             while ((len1 = in.read(bytes1, 0, len1)) != -1) {
 74                 if(len1 < 512){
 75                     byte[] tmpBuf = new byte[len1];
 76                     System.arraycopy(bytes1, 0, tmpBuf, 0, len1);                
 77                     sb.append(new String(tmpBuf));
 78                     tmpBuf = null;
 79                 }else{
 80                     sb.append(new String(bytes1));
 81                 }
 82             }
 83 
 84             in.close();
 85             long end1 = System.currentTimeMillis();
 86             FileInputStreamTime += end1 - begin1;
 87             
 88             //Test BufferedInputStream
 89             long begin2 = System.currentTimeMillis();
 90             int len2 = 512;
 91             byte[] bytes2 = new byte[len2];
 92             buf = new BufferedInputStream(new FileInputStream(f));
 93             while ((len2 = buf.read(bytes2, 0, len2)) != -1) {
 94                 if(len2 < 512){
 95                     byte[] tmpBuf = new byte[len2];
 96                     System.arraycopy(bytes2, 0, tmpBuf, 0, len2);                
 97                     sb.append(new String(tmpBuf));
 98                     tmpBuf = null;
 99                 }else{
100                     sb.append(new String(bytes2));
101                 }
102             }
103 
104             buf.close();
105             long end2 = System.currentTimeMillis();
106             BufferedInputStreamTime += end2 - begin2;
107             
108             //Test FileReader
109             long begin3 = System.currentTimeMillis();
110             reader = new FileReader(f);
111             br = new BufferedReader(reader);
112             String str;
113             while ((str = br.readLine()) != null) {
114                 sb.append(str);
115             }
116             br.close();
117             reader.close();
118             long end3 = System.currentTimeMillis();
119             FileReaderTime += end3 - begin3;
120 
121         } catch (Exception e) {
122             e.printStackTrace();
123         } finally {
124             try {
125                 br.close();
126                 reader.close();
127                 in.close();
128                 buf.close();
129             } catch (Exception e) {
130                 e.printStackTrace();
131             }
132         }
133     }

  测试时,分别对不同大小的数据做500次同样的操作,取得的平均耗时如下:

不同流耗时对比(ms)
  10K 100K 200K 400K
FileOutputStream 0.496 0.794 1.078 1.602
BufferedOutputStream 0.386 0.684 0.878 1.246
FileWriter 0.586 0.996 1.3 1.946
FileInputStream 0.158 0.544 0.984 1.876
BufferedInputStream 0.152 0.396 0.668 1.068
FileReader 0.152 0.608 1.254 2.19

  通过测试,可以发现,就写数据而言,BufferedOutputStream耗时是最短的,而性能FileWriter最差;读数据方面,BufferedInputStream性能最好,而FileReader性能最差劲。所以,以后在涉及到流的读写方面时,要注意一下了~

  FileOutputStream 用于写入诸如图像数据之类的原始字节的流。要写入字符流,请考虑使用 FileWriter。

  BufferedOutputStream的数据成员buf是一个位数组,默认为512字节。当使用write()方法写入数据时,实际上会先将数据写至buf中,当buf已满时才会实现给定的OutputStream对象的write()方法,将buf数据写至目的地,而不是每次都对目的地作写入的动作。BufferedInputStream也是类似。

  另外,有时只是要存储一个对象的成员数据,而不是整个对象的信息,成员数据的类型假设都是Java的基本数据类型,这样的需求不必要使用到与Object输入、输出相关的流对象,可以使用DataInputStream、DataOutputStream来写入或读出数据。在从文件中读出数据时,不用费心地自行判断读入字符串时或读入int类型时何时该停止,使用对应的readUTF()或readInt()方法就可以正确地读入完整类型数据。

  在Java程序执行的过程中,很多数据都是以对象的方式存在于内存中。有时会希望直接将内存中整个对象存储至文件,而不是只存储对象中的某些基本类型成员信息,而在下一次程序运行时,希望可以从文件中读出数据并还原为对象。这时可以使用java.io.ObjectInputStream和java.io.ObjectOutputStream来进行这项工作。

  ByteArrayInputStream可以将一个数组当作流输入的来源,而ByteArrayOutputStream则可以将一个位数组当作流输出的目的地。在这里举一个简单的文件位编辑程序作为例子,您可以打开一个简单的文本文件,其中有简单的A、B、C、D、E、F、G等字符,在读取文件之后,可以直接以程序来指定文件中位的位置来修改所指定的字符。作法是将文件读入数组中,指定数组索引修改元素,然后重新将数组存回文件。

  java.io.Reader和java.io.Writer支持Unicode标准字符集(Character Set)(字节流则只支持ISO-Latin-1 8-bit)。在处理流数据时,会根据系统默认的字符编码来进行字符转换,Reader和Writer是抽象类,在进行文本文件的字符读写时真正会使用其子类,子类通常会重新定义相关的方法。

  如果想要存取的是一个文本文件,可以直接使用java.io.FileReader和java.io.FileWriter类,它们分别继承自InputStreamReader与OutputStreamWriter。可以直接指定文件名称或File对象来打开指定的文本文件,并读入流转换后的字符,字符的转换会根据系统默认的编码(若要指定编码,则还是使用InputStreamReader与OutputStreamWriter)。

  java.io.BufferedReader与java.io.BufferedWriter类各拥有8192字符的缓冲区。当BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并置入缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不足,才会再从文件中读取,使用BufferedWriter时,写入的数据并不会先输出至目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。例如一个文件,通过缓冲区可减少对硬盘的输入/输出动作,以提高文件存取的效率。

  

 

posted @ 2013-05-14 21:53  Scott007  阅读(5217)  评论(1编辑  收藏  举报