Java實現文件拷貝的4種方法

 

轉載:原文轉自

http://blog.csdn.net/ta8210/archive/2008/01/30/2073817.aspx

 

使用 java 進行文件拷貝 相信很多人都會用,,不過效率上是否最好呢?
最近看了看NIO決定試一試 java  NIO 到底有什麼性能的提升.

第一種方法:古老的方式

  public   static   long  forJava(File f1,File f2)  throws  Exception{
  
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中的管道到管道傳輸

     public   static   long  forTransfer(File f1,File f2)  throws  Exception{
        
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:內存文件景象寫(讀文件沒有使用文件景象,有興趣的可以回去試試,,我就不試了,估計會更快)

     public   static   long  forImage(File f1,File f2)  throws  Exception{
        
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種方法:管道對管道

     public   static   long  forChannel(File f1,File f2)  throws  Exception{
        
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+

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章