需求:將指定目錄及其子目錄下所有 .java 文件拷貝到目標目錄,保持目錄結構,拷貝完成後將所有 .java 後綴改為 .txt。
file.isFile() && file.getName().endsWith(".java")。BufferedInputStream/BufferedOutputStream,8KB 緩衝區。.java 文件(含遞歸),則不創建對應目標目錄。renameTo() 修改後綴,處理同名衝突。import java.io.*;
import java.util.*;
public class JavaFileCopyRename {
public static void main(String[] args) throws IOException {
File srcDir = new File("E:\\IO流");
File destDir = new File("E:\\IO");
copyJavaFiles(srcDir, destDir);
renameJavaToTxt(destDir);
System.out.println("拷貝並重命名完成!");
}
/** 遞歸拷貝 .java 文件 */
private static void copy(File src, File dest) throws IOException {
File[] files = src.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".java")) {
// 確保目標目錄存在
if (!dest.exists()) dest.mkdirs();
// 緩衝流拷貝
try (BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(new File(dest, file.getName())))) {
byte[] buffer = new byte[8192];
int len;
while ((len = bis.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
}
} else if (file.isDirectory()) {
// 剪枝:僅當子目錄包含 .java 文件時才遞歸
if (containsJavaFile(file)) {
File newDest = new File(dest, file.getName());
copy(file, newDest);
}
}
}
}
/** 判斷目錄樹中是否包含 .java 文件 */
private static boolean containsJavaFile(File dir) {
File[] files = dir.listFiles();
if (files == null) return false;
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".java")) return true;
if (file.isDirectory() && containsJavaFile(file)) return true;
}
return false;
}
/** 批量將 .java 改為 .txt,處理同名衝突 */
private static void renameJavaToTxt(File dir) throws IOException {
File[] files = dir.listFiles();
if (files == null) return;
for (File file : files) {
if (file.isFile() && file.getName().endsWith(".java")) {
String newName = file.getName().replace(".java", ".txt");
File newFile = new File(file.getParent(), newName);
// 衝突處理:若目標文件已存在,先刪除
if (newFile.exists()) newFile.delete();
file.renameTo(newFile);
} else if (file.isDirectory()) {
renameJavaToTxt(file);
}
}
}
}
BufferedInputStream/OutputStream 減少系統調用次數,8KB 緩衝區平衡內存與速度。使用 try-with-resources 自動關閉流。
containsJavaFile() 先序遍歷判斷,避免創建大量空目錄,節省磁盤空間與文件系統 inode。
同目錄下可能存在 A.java 和 A.txt(或拷貝後產生同名),renameTo() 在目標存在時返回 false,需先 delete() 再重命名。
生產代碼應捕獲 IOException,記錄失敗文件路徑,決定是繼續還是中止。
Files.walkFileTree (NIO.2) 替代手工遞歸,代碼更簡潔、支持訪問屬性過濾。CountDownLatch + 線程池實現多線程並發拷貝,利用多核 CPU 與磁盤並行 IO。此練習涵蓋了文件樹遍歷、流式拷貝、資源管理、衝突解決等 Java IO 核心技能,是文件處理類工具開發的基礎範式。