Java 7:复制和移动文件和目录
路徑對象
路徑對象代表可能包含或不包含文件的目錄序列。 有三種方法構造Path對象:
從現在開始,在所有示例中,我們將使用Paths.get方法。 以下是創建Path對象的一些示例:
//Path string would be "/foo" Paths.get("/foo"); //Path string "/foo/bar" Paths.get("/foo","bar");要操作Path對象,可以使用Path.resolve和Path.relativize方法。 這是使用Path.resolve的示例:
//This is our base path "/foo" Path base = Paths.get("/foo"); //filePath is "/foo/bar/file.txt" while base still "/foo" Path filePath = base.resolve("bar/file.txt");使用Path.resolve方法會將給定的String或Path對象附加到調用Path的末尾,除非給定的String或Path表示絕對路徑,否則將返回給定的路徑,例如:
Path path = Paths.get("/foo"); //resolved Path string is "/usr/local" Path resolved = path.resolve("/usr/local");Path.relativize以相反的方式工作,返回一個新的相對路徑,如果根據調用的Path解析該路徑,則會得到相同的Path字符串。 這是一個例子:
// base Path string "/usr"Path base = Paths.get("/usr");// foo Path string "/usr/foo"Path foo = base.resolve("foo");// bar Path string "/usr/foo/bar"Path bar = foo.resolve("bar");// relative Path string "foo/bar"Path relative = base.relativize(bar);Path類上另一個有用的方法是Path.getFileName,它返回此Path對象表示的最遠元素的名稱,該名稱是實際文件或目錄。 例如:
//assume filePath constructed elsewhere as "/home/user/info.txt" //returns Path with path string "info.txt" filePath.getFileName()//now assume dirPath constructed elsewhere as "/home/user/Downloads" //returns Path with path string "Downloads" dirPath.getFileName()在下一節中,我們將研究如何將Path.resolve和Path.relativize與Files類一起使用來復制和移動文件。
文件類
Files類由使用Path對象處理文件和目錄的靜態方法組成。 盡管Files類中有50多種方法,但目前我們僅討論復制和移動方法。
復制文件
要將一個文件復制到另一個文件,您可以使用(對名稱有任何猜測嗎?)Files.copy方法– copy(路徑源,Path目標,CopyOption…選項)非常簡潔并且沒有匿名內部類,我們確定它是Java嗎? options參數是枚舉,用于指定應如何復制文件。 (實際上有2個不同的Enum類,LinkOption和StandardCopyOption,但是都實現CopyOption接口。)這是Files.copy的可用選項列表:
還有一個StandardCopyOption.ATOMIC_MOVE枚舉,但是如果指定了此選項,則拋出UsupportedOperationException。 如果未指定任何選項,則默認為在目標文件存在或為符號鏈接的情況下引發錯誤。 如果路徑對象是目錄,那么將在目標位置中創建一個空目錄。 (請稍等!在引言中沒有說我們可以復制目錄的全部內容嗎?答案仍然是肯定的,而且即將到來!)這是使用Path使用Path對象將文件復制到另一個文件的示例.resolve和Path.relativize方法:
Path sourcePath ...Path basePath ...Path targetPath ...Files.copy(sourcePath, targetPath.resolve(basePath.relativize(sourcePath));移動文件
移動文件同樣簡單明了– move(路徑源,路徑目標,CopyOption…選項);
可用的StandardCopyOptions枚舉是:
如果使用StandardCopyOption.COPY_ATTRIBUTES調用Files.move,則會引發UnsupportedOperationException。 可以在空目錄上調用Files.move,或者如果它不需要移動目錄內容,例如重新命名,則調用將成功,否則將拋出IOException(我們將在下一節中看到如何移動非空目錄)。 如果目標文件已經存在,則默認為引發Exception。 如果源是符號鏈接,則鏈接本身將被移動,而不是鏈接的目標。 這是Files.move的示例,再次使用Path.relativize和Path.resolve方法:
Path sourcePath ...Path basePath ...Path targetPath ...Files.move(sourcePath, targetPath.resolve(basePath.relativize(sourcePath));復制和移動目錄
Files.walkFileTree是在Files類中找到的更有趣和有用的方法之一。 walkFileTree方法執行文件樹的深度優先遍歷。 有兩個簽名:
Files.walkFileTree的第二個選項使用EnumSet.noneOf(FileVisitOption.class)和Integer.MAX_VALUE調用第一個選項。 在撰寫本文時,只有一個文件訪問選項– FOLLOW_LINKS。 FileVisitor是一個接口,具有定義的四個方法:
所有方法都返回四個可能的FileVisitResult枚舉之一:
為了使生活更輕松,有一個默認的FileVisitor實現,即SimpleFileVisitor(validate參數不為null并返回FileVisitResult.CONTINUE),可以將其子類化,您可以覆蓋您需要使用的方法。 讓我們看一個用于復制整個目錄結構的基本示例。
復制目錄樹示例
讓我們看一下擴展用于復制目錄樹的SimpleFileVisitor的類(為清晰起見,省略了一些詳細信息):
public class CopyDirVisitor extends SimpleFileVisitor<Path> {private Path fromPath;private Path toPath;private StandardCopyOption copyOption = StandardCopyOption.REPLACE_EXISTING;....@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {Path targetPath = toPath.resolve(fromPath.relativize(dir));if(!Files.exists(targetPath)){Files.createDirectory(targetPath);}return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.copy(file, toPath.resolve(fromPath.relativize(file)), copyOption);return FileVisitResult.CONTINUE;} }在第9行中,將遍歷源文件“ fromPath”中的每個目錄,并在目標“ toPath”中創建每個目錄。 在這里,我們可以看到Path對象在處理目錄和文件方面的強大功能。 隨著代碼深入目錄結構,只需分別在fromPath和toPath對象上調用relativize和resolve即可構造正確的Path對象。 我們根本不需要知道我們在目錄樹中的位置,因此不需要繁瑣的StringBuilder操作即可創建正確的路徑。 在第17行,我們看到用于將文件從源目錄復制到目標目錄的Files.copy方法。 接下來是刪除整個目錄樹的簡單示例。
刪除目錄樹示例
在此示例中,SimpleFileVisitor已被子類化,用于刪除目錄結構:
public class DeleteDirVisitor extends SimpleFileVisitor<Path> {@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.delete(file);return FileVisitResult.CONTINUE;}@Overridepublic FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {if(exc == null){Files.delete(dir);return FileVisitResult.CONTINUE;}throw exc;} }如您所見,刪除是一個非常簡單的操作。 只需刪除找到的每個文件,然后在退出時刪除目錄即可。
將Files.walkFileTree與Google Guava結合
前兩個示例雖然有用,但非常“香草”。 讓我們看一下另外兩個示例,它們結合了Google Gauva Function和Predicate接口,它們更具創造力。
public class FunctionVisitor extends SimpleFileVisitor<Path> {Function<Path,FileVisitResult> pathFunction;public FunctionVisitor(Function<Path, FileVisitResult> pathFunction) {this.pathFunction = pathFunction;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {return pathFunction.apply(file);} }在這個非常簡單的示例中,我們將SimpleFileVisitor子類化,以將Function對象作為構造函數參數,并且在遍歷目錄結構時,將該函數應用于每個文件。
public class CopyPredicateVisitor extends SimpleFileVisitor<Path> {private Path fromPath;private Path toPath;private Predicate<Path> copyPredicate;public CopyPredicateVisitor(Path fromPath, Path toPath, Predicate<Path> copyPredicate) {this.fromPath = fromPath;this.toPath = toPath;this.copyPredicate = copyPredicate;}@Overridepublic FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {if (copyPredicate.apply(dir)) {Path targetPath = toPath.resolve(fromPath.relativize(dir));if (!Files.exists(targetPath)) {Files.createDirectory(targetPath);}return FileVisitResult.CONTINUE;}return FileVisitResult.SKIP_SUBTREE;}@Overridepublic FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {Files.copy(file, toPath.resolve(fromPath.relativize(file)));return FileVisitResult.CONTINUE;} }在此示例中,CopyPredicateVisitor接收一個Predicate對象,并且基于返回的布爾值,不會復制部分目錄結構。 我想指出的是,前面兩個示例(除了有用性之外)確實可以在本文后面的源代碼中進行單元測試。
DirUtils
在到目前為止所介紹的所有內容的基礎上,我無法抗拒創建實用程序類DirUtils的機會, 該類是使用以下提供以下方法的目錄的抽象:
//deletes all files but leaves the directory tree in placeDirUtils.clean(Path sourcePath);//completely removes a directory treeDirUtils.delete(Path sourcePath);//replicates a directory treeDirUtils.copy(Path sourcePath, Path targetPath);//not a true move but performs a copy then a delete of a directory treeDirUtils.move(Path sourcePath, Path targetPath);//apply the function to all files visitedDirUtils.apply(Path sourcePath,Path targetPath, Function function);雖然我不愿意說它已經可以生產了,但是寫起來很有趣。
結論
這就包裝了java.nio.file包提供的新的復制和移動功能。 我個人認為這非常有用,并且可以減輕使用Java中文件的痛苦。 還有更多內容,涉及符號鏈接,流復制方法,DirectoryStreams等,因此請務必堅持。 謝謝你的時間。 一如既往地歡迎提出意見和建議。
參考: Java 7的新增功能: JCG合作伙伴的 文件和目錄的復制和移動 ? 比爾·貝杰克(Bill Bejeck)在“ 編碼隨機思想”博客上。
翻譯自: https://www.javacodegeeks.com/2012/02/java-7-copy-and-move-files-and.html
總結
以上是生活随笔為你收集整理的Java 7:复制和移动文件和目录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 理财产品质押多久到账?
- 下一篇: 手机丢了支付宝里的理财产品怎么办?