轉載:原文轉自
http://blog.csdn.net/ta8210/archive/2008/01/30/2073817.aspx
使用 java 進行文件拷貝 相信很多人都會用,,不過效率上是否最好呢?
最近看了看NIO決定試一試 java NIO 到底有什麼性能的提升.
第一種方法:古老的方式
long time = new Date().getTime();
int length = 2097152 ;
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
byte [] buffer = new byte [length];
while ( true ){
int ins = in.read(buffer);
if (ins ==- 1 ){
in.close();
out.flush();
out.close();
return new Date().getTime() - time;
} else
out.write(buffer, 0 ,ins);
}
}
方法的2參數分別是原始文件,和拷貝的目的文件.這裏不做過多介紹.
實現方法很簡單,分別對2個文件構建輸入輸出流,並且使用一個字節數組作爲我們內存的緩存器, 然後使用流從f1 中讀出數據到緩存裏,在將緩存數據寫到f2裏面去.這裏的緩存是2MB的字節數組
第2種方法:使用NIO中的管道到管道傳輸
long time = new Date().getTime();
int length = 2097152 ;
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
FileChannel inC = in.getChannel();
FileChannel outC = out.getChannel();
int i = 0 ;
while ( true ){
if (inC.position() == inC.size()){
inC.close();
outC.close();
return new Date().getTime() - time;
}
if ((inC.size() - inC.position()) < 20971520 )
length = ( int )(inC.size() - inC.position());
else
length = 20971520 ;
inC.transferTo(inC.position(),length,outC);
inC.position(inC.position() + length);
i ++ ;
}
}
實現方法:在第一種實現方法基礎上對輸入輸出流獲得其管道,然後分批次的從f1的管道中像f2的管道中輸入數據每次輸入的數據最大爲2MB
方法3:內存文件景象寫(讀文件沒有使用文件景象,有興趣的可以回去試試,,我就不試了,估計會更快)
long time = new Date().getTime();
int length = 2097152 ;
FileInputStream in = new FileInputStream(f1);
RandomAccessFile out = new RandomAccessFile(f2, " rw " );
FileChannel inC = in.getChannel();
MappedByteBuffer outC = null ;
MappedByteBuffer inbuffer = null ;
byte [] b = new byte [length];
while ( true ){
if (inC.position() == inC.size()){
inC.close();
outC.force();
out.close();
return new Date().getTime() - time;
}
if ((inC.size() - inC.position()) < length){
length = ( int )(inC.size() - inC.position());
} else {
length = 20971520 ;
}
b = new byte [length];
inbuffer = inC.map(MapMode.READ_ONLY,inC.position(),length);
inbuffer.load();
inbuffer.get(b);
outC = out.getChannel().map(MapMode.READ_WRITE,inC.position(),length);
inC.position(b.length + inC.position());
outC.put(b);
outC.force();
}
}
實現方法:跟傷2個例子不一樣,這裏寫文件流沒有使用管道而是使用內存文件映射(假設文件f2在內存中).在循環中從f1的管道中讀取數據到字節數組裏,然後在像內存映射的f2文件中寫數據.
第4種方法:管道對管道
long time = new Date().getTime();
int length = 2097152 ;
FileInputStream in = new FileInputStream(f1);
FileOutputStream out = new FileOutputStream(f2);
FileChannel inC = in.getChannel();
FileChannel outC = out.getChannel();
ByteBuffer b = null ;
while ( true ){
if (inC.position() == inC.size()){
inC.close();
outC.close();
return new Date().getTime() - time;
}
if ((inC.size() - inC.position()) < length){
length = ( int )(inC.size() - inC.position());
} else
length = 2097152 ;
b = ByteBuffer.allocateDirect(length);
inC.read(b);
b.flip();
outC.write(b);
outC.force( false );
}
}
這裏實現方式與第3種實現方式很類似,不過沒有使用內存影射.
下面是對49.3MB的文件進行拷貝的測試時間(毫秒)
Start Copy File... file size:50290KB
CopyFile:b1.rmvb mode:forChannel RunTime:3203
CopyFile:b1.rmvb mode:forImage RunTime:3328
CopyFile:b1.rmvb mode:forJava RunTime:2172
CopyFile:b1.rmvb mode:forTransfer RunTime:1406
End Copy File!
解釋: 在測試結果中看到 古老方式,和管道向管道傳輸是最快的,,,,,爲什麼呢?
我分析是這樣的,由於另外2種方法內部都使用了 字節數組作爲緩存中轉,在加上NIO內部有一個貼近系統的緩存區,這無意就增加了另一個緩存器,所以相對於這2個方法就要慢許多,,如果不使用 字節數組作爲數據中轉的話相信速度會更快的..
不過比較驚訝的是 管道向管道傳輸的速度還是真挺嚇人,,,
我的機器是 IDE硬盤120G 硬盤緩存2MB, 內存1GB, CPU AMD2800+