Java 實現檔案拷貝
阿新 • • 發佈:2020-12-25
技術標籤: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("原始檔不存在, 拷貝失敗");
}
}
注意, 程式碼問題
- 在開發裡面儘量不要使用 do … while 迴圈, 要使用 while 迴圈
- 拷貝的速度堪憂。
第一次改進內容
// 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("原始檔不存在, 拷貝失敗");
}
}