實際專案中常需批量複製檔案並修改副檔名(如醫療影像 .tbi 轉標準 .jpg),需處理目錄遞迴、目標目錄建立、IO 流管理、異常處理等細節。
package com.chen.lucene.image;
import java.io.*;
public class FileFormatConverter {
/**
* 批量複製並轉換檔案副檔名
*
* @param sourceDir 來源目錄路徑
* @param targetDir 目標目錄路徑
* @param oldSuffix 原副檔名(含點,如 ".tbi")
* @param newSuffix 新副檔名(含點,如 ".jpg")
* @throws IOException IO 異常
*/
public void convertAndCopy(String sourceDir, String targetDir,
String oldSuffix, String newSuffix) throws IOException {
File source = new File(sourceDir);
if (!source.exists() || !source.isDirectory()) {
throw new IllegalArgumentException("來源目錄不存在或非目錄: " + sourceDir);
}
File target = new File(targetDir);
if (!target.exists()) {
if (!target.mkdirs()) {
throw new IOException("無法建立目標目錄: " + targetDir);
}
}
File[] files = source.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isFile() && file.getName().endsWith(oldSuffix)) {
String newName = file.getName().replaceFirst(oldSuffix + "$", newSuffix);
File destFile = new File(target, newName);
copyFile(file, destFile);
System.out.printf("已轉換: %s → %s%n", file.getName(), newName);
}
}
}
/**
* 檔案複製核心方法(使用 4KB 緩衝區)
*/
private void copyFile(File source, File dest) throws IOException {
try (FileInputStream fis = new FileInputStream(source);
FileOutputStream fos = new FileOutputStream(dest);
BufferedInputStream bis = new BufferedInputStream(fis, 4096);
BufferedOutputStream bos = new BufferedOutputStream(fos, 4096)) {
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = bis.read(buffer)) != -1) {
bos.write(buffer, 0, bytesRead);
}
bos.flush();
}
}
// 測試主程式
public static void main(String[] args) {
FileFormatConverter converter = new FileFormatConverter();
try {
converter.convertAndCopy(
"E:/temp/3月份數據包",
"E:/temp/img",
".tbi", ".jpg"
);
System.out.println("批量轉換完成!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 錯誤:replaceAll(".tbi", ".jpg") 會匹配任意字元
// 正確:replaceFirst("\\.tbi$", ".jpg") 或 endsWith + substring
String newName = file.getName().replaceFirst(oldSuffix + "$", newSuffix);
| 方案 | 適用場景 | 優點 | 缺點 |
|---|---|---|---|
| 標準 IO (本例) | 中小檔案、跨檔案系統 | 相容性好、可控 | 用戶態/核心態多次拷貝 |
| NIO FileChannel.transferTo | 大檔案、同檔案系統 | 零拷貝、核心態直傳 | 跨檔案系統可能退化 |
| Files.copy (Java 7+) | 通用場景 | API 簡潔、自動選擇最佳策略 | 細節控制較少 |
import java.nio.channels.FileChannel;
import java.nio.file.StandardCopyOption;
public void copyWithNIO(File source, File dest) throws IOException {
try (FileChannel in = FileChannel.open(source.toPath());
FileChannel out = FileChannel.open(dest.toPath(),
StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
// 嘗試零拷貝,大檔案分段傳輸避免阻塞
long transferred = 0;
long size = in.size();
while (transferred < size) {
transferred += in.transferTo(transferred, size - transferred, out);
}
}
}
ExecutorService + CompletableFutureFile.separator 或 Paths.get()listFiles() 可能返回 null 或拋 SecurityException