基于Java?IO?API實現(xiàn)文件復制工具
Java IO API - Java 文件復制工具
這是一個用 Java 編寫的遞歸文件復制工具,模仿了文件系統(tǒng)復制的操作。它從源目錄復制文件到目標目錄,并支持指定復制的最大目錄層級(-depth)。
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.EnumSet;
import java.util.stream.Stream;
import static java.nio.file.FileVisitResult.CONTINUE;
import static java.nio.file.FileVisitResult.SKIP_SUBTREE;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* Sample code that copies files recursively
* from a source directory to a destination folder.
* The maximum number of directory levels to copy
* is specified after -depth.
* The number of files copied is printed
* to standard out.
* You can execute the application using:
* @code java Copy . new -depth 4
*/
public class Copy {
/**
* A {@code FileVisitor} that finds
* all files that match the
* specified pattern.
*/
public static class Replicator
extends SimpleFileVisitor<Path> {
Path source;
Path destination;
public Replicator(Path source, Path destination) {
this.source = source;
this.destination = destination;
}
// Prints the total number of
// files copied to standard out.
void done() throws IOException {
try (Stream<Path> path = Files.list(Paths.get(destination.toUri()))) {
System.out.println("Number of files copied: "
+ path.filter(p -> p.toFile().isFile()).count());
}
}
// Copy a file in destination
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) {
System.out.println("Copy file: " + file);
Path newFile = destination.resolve(source.relativize(file));
try{
Files.copy(file,newFile);
}
catch (IOException ioException){
//log it and move
}
return CONTINUE;
}
// Invoke copy of a directory.
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) {
System.out.println("Copy directory: " + dir);
Path targetDir = destination.resolve(source.relativize(dir));
try {
Files.copy(dir, targetDir, REPLACE_EXISTING, COPY_ATTRIBUTES);
} catch (IOException e) {
System.err.println("Unable to create " + targetDir + " [" + e + "]");
return SKIP_SUBTREE;
}
return CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc == null) {
Path destination = this.destination.resolve(source.relativize(dir));
try {
FileTime time = Files.getLastModifiedTime(dir);
Files.setLastModifiedTime(destination, time);
} catch (IOException e) {
System.err.println("Unable to copy all attributes to: " + destination + " [" + e + "]");
}
} else {
throw exc;
}
return CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) {
if (exc instanceof FileSystemLoopException) {
System.err.println("cycle detected: " + file);
} else {
System.err.format("Unable to copy:" + " %s: %s%n",
file, exc);
}
return CONTINUE;
}
}
static void usage() {
System.err.println("java Copy <source> <destination>" +
" -depth \"<max_level_dir>\"");
System.exit(-1);
}
public static void main(String[] args)
throws IOException {
if (args.length < 4 || !args[2].equals("-depth"))
usage();
Path source = Paths.get(args[0]);
Path destination = Paths.get(args[1]);
int depth = Integer.parseInt(args[3]);
Replicator walk = new Replicator(source, destination);
EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
Files.walkFileTree(source, opts, depth, walk);
walk.done();
}
}功能簡介
該程序會:
- 遞歸地將源目錄中的文件復制到目標目錄。
- 允許通過
-depth參數(shù)指定最大目錄層級。 - 在程序結束時,打印成功復制的文件數(shù)。
例如:
$ java Copy . new -depth 4
會把當前目錄及其子目錄(最多 4 層)中的文件復制到 new 目錄。
示例代碼結構詳解
main()方法:程序入口
public static void main(String[] args) throws IOException {
if (args.length < 4 || !args[2].equals("-depth"))
usage();
Path source = Paths.get(args[0]);
Path destination = Paths.get(args[1]);
int depth = Integer.parseInt(args[3]);
Replicator walk = new Replicator(source, destination);
EnumSet<FileVisitOption> opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
Files.walkFileTree(source, opts, depth, walk);
walk.done();
}
- 輸入?yún)?shù)解析:首先檢查輸入是否符合規(guī)范,若不符合則調(diào)用
usage()打印使用說明。 - 路徑和深度解析:從命令行參數(shù)中提取源目錄、目標目錄和最大目錄深度。
- 文件遍歷:使用
Files.walkFileTree()遞歸遍歷源目錄,進行復制操作。
Replicator類:文件復制核心邏輯
public static class Replicator extends SimpleFileVisitor<Path> {
該類繼承 SimpleFileVisitor<Path> 并重寫了幾個關鍵方法來執(zhí)行復制操作。
構造方法:初始化源路徑與目標路徑
public Replicator(Path source, Path destination) {
this.source = source;
this.destination = destination;
}
source:源目錄路徑;destination:目標目錄路徑。
visitFile()方法:復制文件
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
System.out.println("Copy file: " + file);
Path newFile = destination.resolve(source.relativize(file));
try {
Files.copy(file, newFile);
} catch (IOException ioException) {
// 錯誤日志處理
}
return CONTINUE;
}
- 使用
Files.copy()復制文件到目標路徑。 source.relativize(file)計算文件的相對路徑,以保持源文件夾結構。- 如果復制失敗,會捕獲并記錄異常,但繼續(xù)執(zhí)行。
preVisitDirectory()方法:復制目錄
@Override
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
System.out.println("Copy directory: " + dir);
Path targetDir = destination.resolve(source.relativize(dir));
try {
Files.copy(dir, targetDir, REPLACE_EXISTING, COPY_ATTRIBUTES);
} catch (IOException e) {
System.err.println("Unable to create " + targetDir + " [" + e + "]");
return SKIP_SUBTREE;
}
return CONTINUE;
}
Files.copy()會復制目錄及其屬性。- 如果目錄已存在并且指定了
REPLACE_EXISTING,它將覆蓋該目錄。 - 如果復制失敗,打印錯誤信息并跳過該子目錄(使用
SKIP_SUBTREE)。
postVisitDirectory()方法:復制目錄屬性
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
if (exc == null) {
Path destination = this.destination.resolve(source.relativize(dir));
try {
FileTime time = Files.getLastModifiedTime(dir);
Files.setLastModifiedTime(destination, time);
} catch (IOException e) {
System.err.println("Unable to copy all attributes to: " + destination + " [" + e + "]");
}
} else {
throw exc;
}
return CONTINUE;
}
- 在目錄復制后,復制目錄的最后修改時間等屬性。
- 如果復制失敗,打印錯誤信息。
visitFileFailed()方法:錯誤處理
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
if (exc instanceof FileSystemLoopException) {
System.err.println("Cycle detected: " + file);
} else {
System.err.format("Unable to copy: %s: %s%n", file, exc);
}
return CONTINUE;
}
- 處理訪問失敗的文件。
- 如果檢測到文件系統(tǒng)循環(huán)(符號鏈接等),打印循環(huán)錯誤信息。
done()方法:統(tǒng)計已復制文件數(shù)
void done() throws IOException {
try (Stream<Path> path = Files.list(Paths.get(destination.toUri()))) {
System.out.println("Number of files copied: "
+ path.filter(p -> p.toFile().isFile()).count());
}
}
在文件復制完成后,統(tǒng)計并打印成功復制的文件數(shù)。
usage()方法:程序使用說明
static void usage() {
System.err.println("java Copy <source> <destination> -depth \"<max_level_dir>\"");
System.exit(-1);
}
如果輸入?yún)?shù)無效,打印使用說明并退出程序。
擴展思路與練習建議
| 擴展功能 | 實現(xiàn)方法 |
|---|---|
| 復制文件時跳過某些類型 | 在 visitFile() 方法中加入文件類型判斷(如跳過 .txt 文件) |
| 并行復制大文件夾 | 使用 ExecutorService 執(zhí)行并行文件復制 |
| 復制過程中顯示進度條 | 使用 System.out.print 打印進度信息 |
| 按文件類型篩選復制 | 在 visitFile() 中加入文件類型過濾,例如只復制 .java 文件 |
| 備份和版本控制 | 在 visitFile() 中實現(xiàn)版本號控制,避免覆蓋舊版本 |
錯誤處理建議
- 為
IOException提供更加詳細的日志,例如記錄文件復制失敗的具體原因,或者保存失敗文件列表。 - 為
visitFileFailed()方法添加更多的錯誤類型處理,如權限不足等。
小結
這個 Copy 示例演示了如何使用 Java 的 nio 包進行遞歸文件復制。通過自定義 FileVisitor 類,你可以實現(xiàn)高效且靈活的文件操作。這個工具可以被擴展和定制化,滿足各種實際項目中的需求。
到此這篇關于基于Java IO API實現(xiàn)文件查找和復制工具的文章就介紹到這了,更多相關Java文件查找和復制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
IntelliJ IDEA同步代碼時版本沖突而產(chǎn)生出的incoming partial文件問題的解決辦法
今天小編就為大家分享一篇關于IntelliJ IDEA同步代碼時版本沖突而產(chǎn)生出的incoming partial文件問題的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-10-10
一文帶你徹底了解Java8中的Lambda,函數(shù)式接口和Stream
這篇文章主要為大家詳細介紹了解Java8中的Lambda,函數(shù)式接口和Stream的用法和原理,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學習一下2023-08-08
SpringBoot-JWT生成Token和攔截器的使用(訪問受限資源)
本文主要介紹了SpringBoot-JWT生成Token和攔截器的使用(訪問受限資源),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-05-05
Springboot在有參構造方法類中使用@Value注解取值
這篇文章主要介紹了Springboot在有參構造方法類中使用@Value注解取值,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-06-06

