天天看點

實戰檔案流,完成檔案拷貝 | 帶你學《Java語言進階特性》之五十九

上一篇:借助轉換流打通位元組/字元流的關聯 | 帶你學《Java語言進階特性》之五十八

學習完基本的檔案IO操作,本節将結合檔案拷貝案例,實操代碼,與讀者一起一步步完成檔案拷貝、檔案夾拷貝等功能。

【本節目标】

通過閱讀本節内容,你将從需求分析開始,到方案提出,再到具體實作,一步步完成檔案拷貝的功能,并同時了解到JDK1.9為開發此類功能提供的轉存方法的使用辦法,完成檔案、檔案夾拷貝功能的開發。

綜合實戰:檔案拷貝

在作業系統裡面有一個copy指令,這個指令的主要功能是可以實作檔案的拷貝處理。現在要求模拟這個指令,通過初始化參數輸入拷貝的源檔案與拷貝的目标路徑實作檔案的拷貝處理。

需求分析:

  • 需要實作檔案的拷貝操作,那麼這種拷貝就有可能拷貝各種類型的檔案,是以肯定使用位元組流;
  • 在進行拷貝的時候需要考慮到大檔案的拷貝問題;

實作方案

方案一:使用InputStream将全部要拷貝的内容直接讀取到程式中,而後一次性輸出到目标檔案;

如果現在拷貝的檔案很大,基本上程式就“死“掉了;

方案二:采用部分拷貝,讀取一部分輸出一部分資料。如果現在要采用第二種做法,核心的操作方法:

  |- InputStream:public int read(byte[] b) throws IOException;

  |- OutputStream:public void write(byte[] b, int off, int len) throws IOException;

範例:實作檔案拷貝處理

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

class FileUtil {    //定義一個檔案操作的工具類
    private File srcFile;     //源檔案路徑
    private File desFile;   //目标檔案路徑
    public FileUtil(String src,String des) {
        this(new File(src),new File(des));
    }
    public FileUtil(File srcFile, File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }
    public boolean copy() throws Exception {   //檔案拷貝處理
        if (!this.srcFile.exists()) {   //源檔案必須存在
            System.out.println("拷貝的源檔案不存在!");
            return false;  //源檔案不存在拷貝失敗
        }
        if (!this.desFile.getParentFile().exists()) {
            this.desFile.getParentFile().mkdirs();   //建立父目錄
        }
        byte data[] = new byte[1024];  //開辟一個拷貝的緩沖區
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(this.srcFile);
            output = new FileOutputStream(this.desFile);
            int len = 0;
//           1、讀取資料到數組之中,随後傳回讀取的個數,len = input.read(data)
//           2、判斷個數是否是-1,如果不是則進行寫入  (len = input.read(data))!=-1
//
//            do {
//                len = input.read(data);
//                if(len!=-1){
//                    output.write(data, 0, len);
//                }
//            } while (len != -1);
            while ((len = input.read(data))!=-1){
                output.write(data,0,len);
            }
            return true;
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
            if (output != null) {
                output.close();
            }
        }
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) {   //程式執行出錯
            System.out.println("指令執行錯誤,執行結構:java JavaAPIDemo 拷貝源檔案路徑 拷貝目标檔案路徑");
            System.exit(1);
        }
        long start = System.currentTimeMillis();
        FileUtil fu = new FileUtil(args[0],args[1]);

        System.out.println(fu.copy() ? "檔案拷貝成功!" : "檔案拷貝失敗!");
        long end = System.currentTimeMillis();
        System.out.println("拷貝完成的時間:"+(end - start));  //檔案拷貝成功!拷貝完成時間:192
    }
}           

但是需要注意的是,以上的做法是屬于檔案拷貝最原始的實作,從JDK1.9開始,InputStream和Reader類中都追加有了資料轉存的處理操作方法:

InputStream:

public long transferTo(OutputStream out) throws IOException;           

Reader:

public long transferTo(Writer out) throws IOException;           

範例:使用轉存的方式處理

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

class FileUtil {    //定義一個檔案操作的工具類
    private File srcFile;     //源檔案路徑
    private File desFile;   //目标檔案路徑
    public FileUtil(String src,String des) {
        this(new File(src),new File(des));
    }
    public FileUtil(File srcFile, File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }
    public boolean copy() throws Exception {   //檔案拷貝處理
        if (!this.srcFile.exists()) {   //源檔案必須存在
            System.out.println("拷貝的源檔案不存在!");
            return false;  //源檔案不存在拷貝失敗
        }
        if (!this.desFile.getParentFile().exists()) {
            this.desFile.getParentFile().mkdirs();   //建立父目錄
        }
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(this.srcFile);
            output = new FileOutputStream(this.desFile);
            input.transferTo(output);
            return true;
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
            if (output != null) {
                output.close();
            }
        }
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) {   //程式執行出錯
            System.out.println("指令執行錯誤,執行結構:java JavaAPIDemo 拷貝源檔案路徑 拷貝目标檔案路徑");
            System.exit(1);
        }
        long start = System.currentTimeMillis();
        FileUtil fu = new FileUtil(args[0],args[1]);
        System.out.println(fu.copy() ? "檔案拷貝成功!" : "檔案拷貝失敗!");
        long end = System.currentTimeMillis();
        System.out.println("拷貝完成的時間:"+(end - start));  //檔案拷貝成功!拷貝完成時間:37
    }
}           

此時千萬要注意程式的運作版本,那麼如果說現在要對此程式要求進一步擴充,可以實作一個檔案目錄的拷貝呢?一旦進行了檔案目錄的拷貝,還需要拷貝所有子目錄中的檔案。

範例:檔案夾拷貝

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;

class FileUtil {    //定義一個檔案操作的工具類
    private File srcFile;     //源檔案路徑
    private File desFile;   //目标檔案路徑
    public FileUtil(String src,String des) {
        this(new File(src),new File(des));
    }
    public FileUtil(File srcFile, File desFile) {
        this.srcFile = srcFile;
        this.desFile = desFile;
    }
    public boolean copyDri() throws Exception {
        this.copyImpl(this.srcFile) ;
        try {
            return true;
        }catch (Exception e) {
            return false;
        }
        
    }
    private void copyImpl(File file) throws Exception {   //遞歸操作
        if(file.isDirectory) {   //是目錄
            File result [] =file.listFiles() ; //列出全部目錄組成
            if (result != null) {
                for (int x = 0 ;x < results.length ; x ++) {
                     copyImpl(results[x]);
                }
            }
        }else {   //是檔案
           String newFilePath = file.getPath().replace(this.srcFile.getPath() + File.separator,"");
           Fie newFile = new File(this.desFile,newFilePath);  //拷貝的目标路徑
           this.copyFileImpl(file,newFile);
        }
    }
    private boolean copyFileImpl(File srcFile,File desFile) throws Exception {
        if (!desFile.getParentFile().exists()) {
            desFile.getParentFile().mkdirs();   //建立父目錄
        }
        InputStream input = null;
        OutputStream output = null;
        try {
            input = new FileInputStream(srcFile);
            output = new FileOutputStream(desFile);
            input.transferTo(output);
            return true ;
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
            if (output != null) {
                output.close();
            }
        }
    }     
    public boolean copy() throws Exception {   //檔案拷貝處理
        if (!this.srcFile.exists()) {   //源檔案必須存在
            System.out.println("拷貝的源檔案不存在!");
            return false;  //源檔案不存在拷貝失敗
        }
        return this.copyFileImpl(this.srcFile,this.desFile) ;
    }
}
public class JavaAPIDemo {
    public static void main(String[] args) throws Exception {
        if(args.length != 2) {   //程式執行出錯
            System.out.println("指令執行錯誤,執行結構:java JavaAPIDemo 拷貝源檔案路徑 拷貝目标檔案路徑");
            System.exit(1);
        }
        long start = System.currentTimeMillis();
        FileUtil fu = new FileUtil(args[0],args[1]);
        if (new File(args[0].isFile())) {     //檔案拷貝
            System.out.println(fu.copy() ? "檔案拷貝成功!" : "檔案拷貝失敗!");
        }else {    //目錄拷貝
            System.out.println(fu.copyDir() ? "檔案拷貝成功!" : "檔案拷貝失敗!");
        }
        long end = System.currentTimeMillis();
        System.out.println("拷貝完成的時間:"+(end - start));  //檔案拷貝成功!拷貝完成時間:12173
    }
}           

本程式是IO操作的核心代碼,本程式可以了解,整個IO處理機制也就非常容易了解了。

想學習更多的Java的課程嗎?從小白到大神,從入門到精通,更多精彩不容錯過!免費為您提供更多的學習資源。

本内容視訊來源于

阿裡雲大學 下一篇:教你用不同的編碼标準解碼字元 | 帶你學《Java語言進階特性》之六十 更多Java面向對象程式設計文章檢視此處