而且很多人在使用io包的时候,也只是知道装饰一个Buffer的InputStream或者OutputStream,速度会更快。
那么,在这几者之间,速度上到底有差距没?差距有多大?我们将进行一次IO操作的性能测试。
测试的IO操作为,普通的文件读写(不带Buffer),带Buffer的文件读写,使用nio的管道的普通文件读写,使用nio的管道的随机文件读写。
先写一个TestIO测试类。
/** * 测试IO的抽象类 * @author wing * @date 2012/7/22 */ public abstract class TestIO { private long start, time; public void testTime(){ start = System.nanoTime(); test(); time = System.nanoTime() - start; System.out.format("%.3f\n", time/1.0e9); } protected abstract void test(); }
用来测试test方法的操作耗时。
然后是各种IO操作的FileIO类。
package org.wing.nio.test; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.IntBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; /** * IO和NIO文件操作 * @author wing * @date 2012/7/22 */ public class FileIO { private static final int count = 400000; private static final int bufferSize = 400000; /** * 不使用Buffer包装的输出流写入文件 */ public static void writeIO(String fileName){ DataOutputStream mDos = null; try { mDos = new DataOutputStream(new FileOutputStream(new File(fileName))); for(int i = 0; i < count; i++){ mDos.writeInt(1); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mDos != null){ try { mDos.close(); } catch (IOException e) { System.out.println("Stream Close Exception:" + e.toString()); } } } } /** * 不使用Buffer包装输入流读入文件 */ public static void readIO(String fileName){ DataInputStream mDis = null; try { mDis = new DataInputStream(new FileInputStream(new File(fileName))); for(int i = 0; i < count; i++){ mDis.readInt(); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mDis != null){ try { mDis.close(); } catch (IOException e) { System.out.println("Stream Close Exception:" + e.toString()); } } } } /** * 使用Buffer包装的输出流写入文件 */ public static void writeIOWithBuffer(String fileName){ DataOutputStream mDos = null; try { mDos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(new File(fileName)))); for(int i = 0; i < count; i++){ mDos.writeInt(1); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mDos != null){ try { mDos.close(); } catch (IOException e) { System.out.println("Stream Close Exception:" + e.toString()); } } } } /** * 使用Buffer包装输入流读入文件 */ public static void readIOWithBuffer(String fileName){ DataInputStream mDis = null; try { mDis = new DataInputStream(new BufferedInputStream(new FileInputStream(new File(fileName)))); for(int i = 0; i < count; i++){ mDis.readInt(); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mDis != null){ try { mDis.close(); } catch (IOException e) { System.out.println("Stream Close Exception:" + e.toString()); } } } } /** * 使用NIO管道来进行数据写入 */ public static void writeNIO(String fileName){ FileChannel mFc = null; try { mFc = new FileOutputStream(new File(fileName)).getChannel(); IntBuffer mBuffer = IntBuffer.allocate(bufferSize); for(int i = 0; i < count; i++){ mBuffer.put(1); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); }finally{ if(mFc != null){ try { mFc.close(); } catch (IOException e) { System.out.println("Channel Close Exception:" + e.toString()); } } } } /** * 使用NIO管道来进行数据读取 */ public static void readNIO(String fileName){ FileChannel mFc = null; try { mFc = new FileInputStream(new File(fileName)).getChannel(); IntBuffer mBuffer = IntBuffer.allocate(bufferSize); for(int i = 0; i < count; i++){ mBuffer.get(); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); }finally{ if(mFc != null){ try { mFc.close(); } catch (IOException e) { System.out.println("Channel Close Exception:" + e.toString()); } } } } /** * 使用NIO管道来进行数据写入 */ public static void writeNIOWithRan(String fileName){ FileChannel mFc = null; try { mFc = new RandomAccessFile(fileName, "rw").getChannel(); IntBuffer mBuffer = mFc.map(MapMode.READ_WRITE, 0, 4 * bufferSize).asIntBuffer(); for(int i = 0; i < count; i++){ mBuffer.put(1); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mFc != null){ try { mFc.close(); } catch (IOException e) { System.out.println("Channel Close Exception:" + e.toString()); } } } } /** * 使用NIO管道来进行数据读取 */ public static void readNIOWithRan(String fileName){ FileChannel mFc = null; try { mFc = new RandomAccessFile(fileName, "rw").getChannel(); IntBuffer mBuffer = mFc.map(MapMode.READ_WRITE, 0, 4 * bufferSize).asIntBuffer(); for(int i = 0; i < count; i++){ mBuffer.get(); } } catch (FileNotFoundException e) { System.out.println("File Not Found:" + e.toString()); } catch (IOException e) { System.out.println("IO Exception:" + e.toString()); }finally{ if(mFc != null){ try { mFc.close(); } catch (IOException e) { System.out.println("Channel Close Exception:" + e.toString()); } } } } }
大家可以看到,上面有各种IO的操作。操作次数是读写int类型400000次。
然后是我们的主类。
package org.wing.nio.test; public class MainClass { public static void main(String[] args) { final String fileName = "test"; TestIO[] testList = new TestIO[] { new TestIO() { @Override protected void test() { FileIO.writeIO(fileName); } }, new TestIO() { @Override protected void test() { FileIO.readIO(fileName); } }, new TestIO() { @Override protected void test() { FileIO.writeIOWithBuffer(fileName); } }, new TestIO() { @Override protected void test() { FileIO.readIOWithBuffer(fileName); } }, new TestIO() { @Override protected void test() { FileIO.writeNIO(fileName); } }, new TestIO() { @Override protected void test() { FileIO.readNIO(fileName); } }, new TestIO() { @Override protected void test() { FileIO.writeNIOWithRan(fileName); } }, new TestIO() { @Override protected void test() { FileIO.readNIOWithRan(fileName); } }, }; for(TestIO testIO : testList){ testIO.testTime(); } } }
新建了一个TestIO类的数组,分别重写test方法,使用自己的IO操作。然后循环执行TestIO的testTime方法。
运行程序,看看结果。
大家可以看到,在不使用Buffer装饰的IO操作中,进行400000次的int写操作耗时5.764秒,读操作3.301秒。而使用Buffer装饰的IO操作读0.021秒,写0.020秒。 但是直接使用nio的管道进行普通文件和随机读写文件的IO操作,耗时更小,写操作仅0.010秒,读操作仅0.006秒。
在第一次测试中,大家可以很明显的看出来,使用Buffer装饰的IO操作已经远远的超过了不使用Buffer装饰的IO操作的速度。而在400000次操作中与nio包的管道读写速度相差无几。
那么,io包跟nio包的IO读写速度就真的差不多么?
我们进行下一轮的测试。
注释掉,不使用Buffer装饰的TestIO类的创建,因为我们要增加IO操作次数了,不使用Buffer装饰的IO操作将会极为耗时。
我们将IO操作次数改为4000000次。
运行查看结果。
大家可以看到,在4000000次的IO操作中,buffer的普通IO操作读写耗时在0.6秒左右,而使用管道的IO操作,读写时间在0.05秒左右,使用随机访问文件的管道的IO操作读写时间在0.065秒左右。
那么,我们继续增加IO操作次数,增加到40000000次。
运行程序,看看结果。
大家可以看到,增加了IO操作次数之后,io包里带buffer的IO操作,写操作耗时达到了5.8秒,而读操作达到了1.7秒!!但是使用nio包管道的IO操作,写操作耗时仅0.33秒,读操作耗时仅0.27秒。使用随机访问文件的管道的IO操作耗时略微高一点,写操作0.57秒,读操作0.4秒。
由此可以看出,即使在jdk 1.4之后重写了io包,提升了效率。但是在达到一定的IO次数之后,io包与nio包管道操作的效率的差距已经越来越大了。而使用随机访问文件的普通IO操作,虽然耗时略高一点,但整体不受太大影响。不过我这里没进行seek操作,然后读写。估计还是会影响比较大的效率。
当然,在我们日常开发中,使用io包的装饰buffer的IO操作已经够用了。不过这也从另外一方面显示出了nio包的强大与高效。
测试可能有很多地方不正确,但整体应该没有很大的问题,大家看看即可。
转载请注明出处:http://blog.csdn.net/ml3947