Java中把一個(gè)文件夾下的所有文件復(fù)制到另一個(gè)文件夾的完整實(shí)現(xiàn)方案
在Java中把一個(gè)文件夾下的所有文件復(fù)制到另一個(gè)文件夾(支持多級(jí)目錄、空文件夾、文件覆蓋等場(chǎng)景),以下是基于Java原生API的完整實(shí)現(xiàn)方案(兼容Java 8+,無(wú)需額外依賴(lài)):
一、核心實(shí)現(xiàn)思路
- 校驗(yàn)源文件夾:確保源文件夾存在且是合法目錄;
- 創(chuàng)建目標(biāo)文件夾:若目標(biāo)文件夾不存在,自動(dòng)遞歸創(chuàng)建(包括多級(jí)父目錄);
- 遞歸遍歷源文件:遍歷源文件夾下的所有文件/子目錄,區(qū)分文件和目錄分別處理;
- 復(fù)制文件:對(duì)文件使用字節(jié)流/通道復(fù)制,對(duì)目錄遞歸創(chuàng)建并復(fù)制其內(nèi)文件;
- 異常處理:捕獲IO異常,保證復(fù)制過(guò)程的健壯性。
二、完整可運(yùn)行代碼
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
/**
* 文件夾復(fù)制工具類(lèi)(支持多級(jí)目錄、文件覆蓋)
*/
public class FolderCopyUtil {
/**
* 核心方法:復(fù)制源文件夾下的所有文件/目錄到目標(biāo)文件夾
* @param sourceDirPath 源文件夾路徑(如:D:/source)
* @param targetDirPath 目標(biāo)文件夾路徑(如:D:/target)
* @throws IOException IO異常(文件無(wú)法讀取/寫(xiě)入)
*/
public static void copyFolder(String sourceDirPath, String targetDirPath) throws IOException {
File sourceDir = new File(sourceDirPath);
File targetDir = new File(targetDirPath);
// 步驟1:校驗(yàn)源文件夾合法性
if (!sourceDir.exists()) {
throw new IOException("源文件夾不存在:" + sourceDirPath);
}
if (!sourceDir.isDirectory()) {
throw new IOException("路徑不是合法文件夾:" + sourceDirPath);
}
// 步驟2:創(chuàng)建目標(biāo)文件夾(遞歸創(chuàng)建多級(jí)目錄,已存在則無(wú)影響)
if (!targetDir.exists()) {
boolean isCreated = targetDir.mkdirs();
if (!isCreated) {
throw new IOException("目標(biāo)文件夾創(chuàng)建失?。? + targetDirPath);
}
}
// 步驟3:遍歷源文件夾下的所有文件/子目錄
File[] files = sourceDir.listFiles();
if (files == null) { // 源文件夾為空或無(wú)讀取權(quán)限
return;
}
for (File file : files) {
String targetFilePath = targetDirPath + File.separator + file.getName();
if (file.isFile()) {
// 步驟4:復(fù)制文件(覆蓋已存在的目標(biāo)文件)
copyFile(file, new File(targetFilePath));
System.out.println("文件復(fù)制成功:" + file.getPath() + " → " + targetFilePath);
} else if (file.isDirectory()) {
// 步驟5:遞歸復(fù)制子目錄
copyFolder(file.getPath(), targetFilePath);
System.out.println("目錄復(fù)制成功:" + file.getPath() + " → " + targetFilePath);
}
}
}
/**
* 輔助方法:復(fù)制單個(gè)文件(使用NIO FileChannel,效率更高)
* @param sourceFile 源文件
* @param targetFile 目標(biāo)文件
* @throws IOException IO異常
*/
private static void copyFile(File sourceFile, File targetFile) throws IOException {
// 覆蓋目標(biāo)文件(若已存在則刪除后重建)
if (targetFile.exists()) {
boolean isDeleted = targetFile.delete();
if (!isDeleted) {
throw new IOException("目標(biāo)文件覆蓋失敗,無(wú)法刪除已有文件:" + targetFile.getPath());
}
}
// 使用NIO通道復(fù)制(比傳統(tǒng)字節(jié)流效率更高)
try (FileInputStream fis = new FileInputStream(sourceFile);
FileOutputStream fos = new FileOutputStream(targetFile);
FileChannel inChannel = fis.getChannel();
FileChannel outChannel = fos.getChannel()) {
// 批量傳輸字節(jié),避免逐字節(jié)復(fù)制,提升大文件復(fù)制效率
long transferred = 0;
long fileSize = inChannel.size();
while (transferred < fileSize) {
transferred += inChannel.transferTo(transferred, fileSize - transferred, outChannel);
}
}
}
// 測(cè)試方法
public static void main(String[] args) {
// 替換為你的源文件夾和目標(biāo)文件夾路徑
String sourceDir = "D:/test/source";
String targetDir = "D:/test/target";
try {
copyFolder(sourceDir, targetDir);
System.out.println("文件夾復(fù)制完成!");
} catch (IOException e) {
System.err.println("文件夾復(fù)制失敗:" + e.getMessage());
e.printStackTrace();
}
}
}
三、關(guān)鍵細(xì)節(jié)說(shuō)明
核心API解析
File.mkdirs():遞歸創(chuàng)建多級(jí)目錄(如目標(biāo)路徑是D:/a/b/c,若a/b不存在,會(huì)自動(dòng)創(chuàng)建),區(qū)別于mkdir()(僅創(chuàng)建單級(jí)目錄);FileChannel.transferTo():NIO通道復(fù)制文件,直接利用操作系統(tǒng)底層IO,比傳統(tǒng)InputStream/OutputStream逐字節(jié)復(fù)制效率高,尤其適合大文件;try-with-resources:自動(dòng)關(guān)閉流/通道,避免手動(dòng)關(guān)閉遺漏導(dǎo)致的資源泄露。
關(guān)鍵特性適配
- 覆蓋目標(biāo)文件:復(fù)制前先刪除已存在的目標(biāo)文件,確保復(fù)制的是最新文件;若需避免覆蓋,可在
copyFile方法中增加判斷:
if (targetFile.exists()) {
System.out.println("目標(biāo)文件已存在,跳過(guò)復(fù)制:" + targetFile.getPath());
return;
}
- 空文件夾處理:源文件夾為空時(shí),
listFiles()返回null,直接返回不報(bào)錯(cuò);目標(biāo)空文件夾會(huì)正常創(chuàng)建; - 多級(jí)目錄復(fù)制:通過(guò)遞歸調(diào)用
copyFolder,支持復(fù)制源文件夾下的所有子目錄及文件; - 權(quán)限防護(hù):若源文件無(wú)讀取權(quán)限/目標(biāo)文件夾無(wú)寫(xiě)入權(quán)限,會(huì)拋出
IOException并提示具體原因。
路徑兼容性
- 使用
File.separator代替硬編碼的/或\,兼容Windows(\)和Linux/Mac(/)系統(tǒng); - 支持絕對(duì)路徑(如
D:/test)和相對(duì)路徑(如./source)。
四、拓展:Java 7+ Files工具類(lèi)實(shí)現(xiàn)(更簡(jiǎn)潔)
若使用Java 7及以上版本,可借助java.nio.file.Files工具類(lèi)簡(jiǎn)化代碼,無(wú)需手動(dòng)實(shí)現(xiàn)文件復(fù)制邏輯:
import java.io.IOException;
import java.nio.file.*;
public class FolderCopyWithFilesUtil {
public static void copyFolder(String sourceDirPath, String targetDirPath) throws IOException {
Path sourcePath = Paths.get(sourceDirPath);
Path targetPath = Paths.get(targetDirPath);
// 遞歸復(fù)制目錄,配置復(fù)制選項(xiàng)(覆蓋已存在文件)
Files.walkFileTree(sourcePath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
// 創(chuàng)建目標(biāo)目錄(遞歸)
Path targetDir = targetPath.resolve(sourcePath.relativize(dir));
if (!Files.exists(targetDir)) {
Files.createDirectories(targetDir);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
// 復(fù)制文件(覆蓋已存在)
Path targetFile = targetPath.resolve(sourcePath.relativize(file));
Files.copy(file, targetFile, StandardCopyOption.REPLACE_EXISTING);
System.out.println("復(fù)制文件:" + file + " → " + targetFile);
return FileVisitResult.CONTINUE;
}
});
}
public static void main(String[] args) {
String sourceDir = "D:/test/source";
String targetDir = "D:/test/target";
try {
copyFolder(sourceDir, targetDir);
System.out.println("復(fù)制完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
總結(jié)
- 核心方案:
- 基礎(chǔ)版:使用
File+FileChannel實(shí)現(xiàn),兼容性好,適合理解底層邏輯; - 簡(jiǎn)潔版:使用
Files.walkFileTree(Java 7+),代碼更簡(jiǎn)潔,無(wú)需手動(dòng)處理遞歸和文件復(fù)制;
- 基礎(chǔ)版:使用
- 關(guān)鍵要點(diǎn):
- 先校驗(yàn)源文件夾合法性,自動(dòng)創(chuàng)建目標(biāo)多級(jí)目錄;
- 區(qū)分文件/目錄,文件用通道復(fù)制(高效),目錄遞歸處理;
- 處理文件覆蓋/權(quán)限問(wèn)題,保證復(fù)制健壯性;
- 適配場(chǎng)景:支持任意大小文件、多級(jí)目錄、跨系統(tǒng)路徑,滿(mǎn)足絕大多數(shù)文件夾復(fù)制需求。
以上就是Java中把一個(gè)文件夾下的所有文件復(fù)制到另一個(gè)文件夾的完整實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于Java把一個(gè)文件夾所有文件復(fù)制到另一個(gè)文件夾的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java實(shí)現(xiàn)解析并生成xml原理實(shí)例詳解
這篇文章主要介紹了Java實(shí)現(xiàn)解析并生成xml原理實(shí)例詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-06-06
Java診斷工具Arthas的快速入門(mén)與實(shí)踐
在Java開(kāi)發(fā)中,我們經(jīng)常會(huì)遇到各種性能問(wèn)題、內(nèi)存泄漏、線(xiàn)程阻塞等問(wèn)題,這些問(wèn)題往往難以通過(guò)常規(guī)的日志和監(jiān)控工具來(lái)定位和解決,Arthas作為一款開(kāi)源的Java診斷工具,提供了強(qiáng)大的實(shí)時(shí)監(jiān)控和診斷功能,本文將詳細(xì)介紹Arthas的安裝、基本使用以及一些常用命令2025-02-02
VsCode搭建Java開(kāi)發(fā)環(huán)境的方法
這篇文章主要介紹了VsCode搭建Java開(kāi)發(fā)環(huán)境的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
java引用類(lèi)型WeakReference用法及原理詳解
Java弱引用(WeakReference)是一種特殊的引用類(lèi)型,當(dāng)垃圾回收器運(yùn)行時(shí),無(wú)論內(nèi)存是否充足,只要發(fā)現(xiàn)對(duì)象僅被弱引用指向,就會(huì)立即回收該對(duì)象,這篇文章主要介紹了java引用類(lèi)型WeakReference用法及原理的相關(guān)資料,需要的朋友可以參考下2026-01-01
Kotlin Coroutines執(zhí)行異步加載示例詳解
這篇文章主要給大家介紹了關(guān)于Kotlin Coroutines執(zhí)行異步加載的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。2018-01-01
Java實(shí)現(xiàn)一個(gè)達(dá)達(dá)租車(chē)系統(tǒng)的步驟詳解
這篇文章主要給大家介紹了利用Java實(shí)現(xiàn)一個(gè)達(dá)達(dá)租車(chē)系統(tǒng)的步驟,文中給出了詳細(xì)的實(shí)現(xiàn)思路和示例代碼,并在文末給出了完整的源碼供大家學(xué)習(xí)下載,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-04-04
java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案舉例
當(dāng)你使用一個(gè)未定義或未導(dǎo)入的類(lèi)時(shí),編譯器會(huì)報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于java:找不到符號(hào)報(bào)錯(cuò)的排錯(cuò)方案,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01

