1. 程式人生 > 其它 >Java 實現檔案拷貝

Java 實現檔案拷貝

技術標籤:Java演算法及JDK原始碼探究日常小知識隨筆java演算法

文章目錄

案例: 原始實現, 未優化

package com.cwq.beyond;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; /** * 建立一個專門負責檔案拷貝處理的類, 該類具備如下功能: * 1. 需要判斷拷貝的原始檔是否存在 * 2. 需要判斷目標檔案父路徑是否存在, 如果不存在則應該建立 * 3. 需要進行檔案拷貝操作的處理 * @author DHL * */ class CopyUtil{ // 這個類不需要任何的屬性, 所以建議將構造方法私有化,使用 static 方法 private CopyUtil() {} // 將構造方法私有化 /** * 判斷要拷貝的源路徑是否存在 * @param path 輸入的源路徑資訊 * @return 如果該路徑真實存在, 返回 true , 否則返回 false */
public static boolean fileExists(String path) { return new File(path).exists(); } public static void createParentDirectory(String path) { File file = new File(path); if (!file.getParentFile().exists()) { file.getParentFile().mkdirs(); } } /** * 實現檔案拷貝的操作處理 * @param srcPath 原始檔路徑 * @param desPath 目標檔案路徑 * @return 拷貝完成返回 true 否則返回false */
public static boolean copy(String srcPath, String desPath) { boolean flag = false; File inFile = new File(srcPath); File outFile = new File(desPath); InputStream input = null; OutputStream output = null; try { input = new FileInputStream(inFile); output = new FileOutputStream(outFile); copyHandle(input, output); flag = true; // 如果沒有發生異常, 則一定會執行此語句 } catch (Exception e) { flag = false; } finally { try { input.close(); output.close(); } catch (Exception e2) { } } return flag; } private static void copyHandle(InputStream input, OutputStream output) throws IOException { long start = System.currentTimeMillis(); // InputStream 有一個讀取單個位元組的方法: int read(); // OutputStream 有一個輸出單個位元組的方法: void write(int data) int temp = 0; do { temp = input.read(); // 讀取單個位元組資料 output.write(temp); }while(temp != -1); // 如果資料繼續讀取 long end = System.currentTimeMillis(); System.out.println("[統計]拷貝檔案所花費的時間為 :"+ (end-start) + "毫秒"); } } public class Copy { public static void main(String[] args) { if (args.length != 2) { // 現在的引數不是兩個 System.out.println("錯誤的執行方式, 命令呼叫: java Copy 原始檔路徑 目標檔案路徑"); System.exit(1); // 系統退出 } if(CopyUtil.fileExists(args[0])) { // 必須要判斷要拷貝的原始檔必須存在 CopyUtil.createParentDirectory(args[1]); // 建立目標的父目錄 System.out.println(CopyUtil.copy(args[0],args[1]) ? "檔案拷貝成功~" : "拷貝失敗!"); }else System.out.println("原始檔不存在, 拷貝失敗"); } }

在這裡插入圖片描述

注意, 程式碼問題

  1. 在開發裡面儘量不要使用 do … while 迴圈, 要使用 while 迴圈
  2. 拷貝的速度堪憂。

第一次改進內容

//		do {
//			temp = input.read();  // 讀取單個位元組資料
//			output.write(temp);
//		}while(temp != -1);  // 如果資料繼續讀取
		
		//1. temp = input.read(), 表示讀取輸入流中的一個位元組
		//2. (temp = input.read()) != -1, 判斷這個讀取後的位元組(儲存在temp)是否為 -1, 如果不是表示有內容
		while ((temp = input.read()) != -1) {
			output.write(temp);
		}

在這裡插入圖片描述
以上的方式還是針對於一個位元組的模式完成的, 實際之中如果檔案太大, 這種做法一定不可取。

第二次改進: 解決讀取慢的問題

如果要解決讀取慢的問題, 那麼就需要加大一個快取, 也就是說一次性讀取多個位元組資料, 那麼就要開闢一個位元組陣列

核心程式碼

	//1. temp = input.read(), 表示將資料讀取到位元組陣列之中, 而後返回資料讀取個數
		//2. (temp = input.read()) != -1, 判斷這個陣列的讀取個數是否為 -1, 如果不是表示有內容
		while ((temp = input.read(data)) != -1) {
			output.write(data,0,temp);  // 輸出讀取到的部分位元組陣列
		}
		

方法程式碼, 以後使用最多的形式

private static void copyHandle(InputStream input, OutputStream output) throws IOException {
		long start = System.currentTimeMillis();
		// InputStream 有一個讀取單個位元組的方法: int read();
		// OutputStream 有一個輸出單個位元組的方法: void write(int data)
		int temp = 0;
		byte data [] = new byte[2048];
		
		
		
//		do {
//			temp = input.read();  // 讀取單個位元組資料
//			output.write(temp);
//		}while(temp != -1);  // 如果資料繼續讀取
		
		//1. temp = input.read(), 表示將資料讀取到位元組陣列之中, 而後返回資料讀取個數
		//2. (temp = input.read()) != -1, 判斷這個陣列的讀取個數是否為 -1, 如果不是表示有內容
		while ((temp = input.read(data)) != -1) {
			output.write(data,0,temp);  // 輸出讀取到的部分位元組陣列
		}
		
		long end = System.currentTimeMillis();
		System.out.println("拷貝檔案所花費的時間為 :"+ (end-start) + "毫秒");
	}

在這裡插入圖片描述
==如果現在要求處理的資料都在InputStream裡面輸出, 就採用以上的模型 ==

原始碼

package com.cwq.beyond;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 建立一個專門負責檔案拷貝處理的類, 該類具備如下功能: 
 * 1. 需要判斷拷貝的原始檔是否存在
 * 2. 需要判斷目標檔案父路徑是否存在, 如果不存在則應該建立
 * 3. 需要進行檔案拷貝操作的處理
 * @author DHL
 *
 */
class CopyUtil{  // 這個類不需要任何的屬性, 所以建議將構造方法私有化,使用 static 方法
	private CopyUtil() {}  // 將構造方法私有化
	/**
	 *  判斷要拷貝的源路徑是否存在
	 * @param path	輸入的源路徑資訊
	 * @return 如果該路徑真實存在, 返回 true , 否則返回 false
	 */
	public static boolean fileExists(String path) {
		return new File(path).exists();
	}
	
	public static void createParentDirectory(String path) {
		File file = new File(path);
		if (!file.getParentFile().exists()) {
			file.getParentFile().mkdirs();
		}
	}
	
	/**
	 * 實現檔案拷貝的操作處理
	 * @param srcPath 原始檔路徑
	 * @param desPath 目標檔案路徑
	 * @return 拷貝完成返回 true 否則返回false
	 */
	public static boolean copy(String srcPath, String desPath) {
		boolean flag = false;
		File inFile = new File(srcPath);
		File outFile = new File(desPath);
		InputStream input = null;
		OutputStream output = null;
		try {
			input = new FileInputStream(inFile);
			output = new FileOutputStream(outFile);
			copyHandle(input, output);
			flag = true;  // 如果沒有發生異常, 則一定會執行此語句
		} catch (Exception e) {
			flag = false;
		} finally {
			try {
				input.close();
				output.close();
			} catch (IOException e2) { }
		}
		return flag;
	}
	
	private static void copyHandle(InputStream input, OutputStream output) throws IOException {
		long start = System.currentTimeMillis();
		// InputStream 有一個讀取單個位元組的方法: int read();
		// OutputStream 有一個輸出單個位元組的方法: void write(int data)
		int temp = 0;
		byte data [] = new byte[2048];
		
		
		
//		do {
//			temp = input.read();  // 讀取單個位元組資料
//			output.write(temp);
//		}while(temp != -1);  // 如果資料繼續讀取
		
		//1. temp = input.read(), 表示將資料讀取到位元組陣列之中, 而後返回資料讀取個數
		//2. (temp = input.read()) != -1, 判斷這個陣列的讀取個數是否為 -1, 如果不是表示有內容
		while ((temp = input.read(data)) != -1) {
			output.write(data,0,temp);  // 輸出讀取到的部分位元組陣列
		}
		
		long end = System.currentTimeMillis();
		System.out.println("拷貝檔案所花費的時間為 :"+ (end-start) + "毫秒");
	}
	
}

public class Copy {
	public static void main(String[] args) {
		if (args.length != 2) { // 現在的引數不是兩個
			System.out.println("錯誤的執行方式, 命令呼叫: java Copy 原始檔路徑 目標檔案路徑");
			System.exit(1); // 系統退出
		} 
		if(CopyUtil.fileExists(args[0])) {  // 必須要判斷要拷貝的原始檔必須存在
			CopyUtil.createParentDirectory(args[1]);  // 建立目標的父目錄
			System.out.println(CopyUtil.copy(args[0],args[1]) ? "檔案拷貝成功~" : "拷貝失敗!");
		}else
			System.out.println("原始檔不存在, 拷貝失敗");
		
	}
}