而且很多人在使用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