Files的常用方法都有哪些?

Java nio.2中的java.nio.file.files類提供了豐富的文件操作功能,分為四大類。1. 文件與目錄的創建、刪除與移動:createfile、createdirectory、createdirectories用于創建文件或目錄;delete和deleteifexists用于刪除;copy和move用于復制和移動。2. 文件內容讀寫:readallbytes和readalllines用于快速讀取文件內容;write用于寫入字節或文本。3. 文件屬性與狀態查詢:exists、isdirectory、isregularfile等方法檢查狀態;size、getlastmodifiedtime獲取屬性;readattributes批量獲取詳細屬性信息。4. 文件系統遍歷:list列出目錄內容;walk遞歸遍歷目錄樹;find在遍歷中按條件過濾文件。這些方法結合stream api使文件處理更簡潔高效,適用于各類文件系統操作場景。

Files的常用方法都有哪些?

java.nio.file.Files是Java NIO.2中一個非常核心的工具類,它提供了大量靜態方法,用于執行文件和目錄的各種操作。簡單來說,它就是我們日常處理文件系統時最常用、也最強大的幫手,覆蓋了從創建、刪除、復制、移動到讀寫、屬性查詢乃至文件系統遍歷的方方面面。它的設計理念比老舊的java.io.File更現代,更注重異常處理和性能,也更好地融入了Java 8以來的Stream API。

Files的常用方法都有哪些?

解決方案

Files類的方法非常多,但我們可以從功能上大致分為幾類,這樣理解起來會清晰很多。我平時用得最多的,不外乎就是那些對文件或目錄進行生命周期管理、內容讀寫以及屬性查詢的操作。

Files的常用方法都有哪些?

1. 文件與目錄的創建、刪除與移動

這是最基礎也最常用的。

Files的常用方法都有哪些?

  • createFile(Path path, FileAttribute>… attrs): 創建一個空文件。如果文件已存在,會拋出FileAlreadyExistsException。
  • createDirectory(Path dir, FileAttribute>… attrs): 創建一個新目錄。父目錄必須存在。
  • createDirectories(Path dir, FileAttribute>… attrs): 創建目錄,如果父目錄不存在,也會一并創建。這個非常實用,省去了我們手動檢查和創建父目錄的麻煩。
  • delete(Path path): 刪除文件或空目錄。如果文件或目錄不存在,或者目錄不為空,會拋出異常。
  • deleteIfExists(Path path): 刪除文件或空目錄,如果不存在則不執行任何操作,也不會拋出異常。我個人更喜歡用這個,省心。
  • copy(Path source, Path target, CopyOption… options): 復制文件或目錄。可以指定復制選項,比如StandardCopyOption.REPLACE_EXISTING(覆蓋目標文件)或StandardCopyOption.COPY_ATTRIBUTES(復制文件屬性)。
  • move(Path source, Path target, CopyOption… options): 移動或重命名文件或目錄。和copy類似,也有各種選項。

2. 文件內容的讀寫

Files提供了一些非常方便的方法來快速讀寫文件內容,尤其適合處理小到中等大小的文件。

  • readAllBytes(Path path): 讀取文件所有字節到byte[]數組。
  • readAllLines(Path path, Charset cs): 讀取文件所有行到List。這個方法簡直是文本處理的利器,一行代碼搞定讀取,省去了手動循環讀取行的麻煩。
  • write(Path path, byte[] bytes, OpenOption… options): 將字節數組寫入文件。
  • write(Path path, Iterable extends CharSequence> lines, Charset cs, OpenOption… options): 將字符串集合(比如List)逐行寫入文件。

3. 文件屬性與狀態查詢

在進行操作前,我們經常需要檢查文件或目錄的狀態。

  • exists(Path path, LinkOption… options): 檢查文件或目錄是否存在。
  • notExists(Path path, LinkOption… options): 檢查文件或目錄是否不存在。
  • isDirectory(Path path, LinkOption… options): 檢查是否是目錄。
  • isRegularFile(Path path, LinkOption… options): 檢查是否是普通文件。
  • isReadable(Path path): 檢查文件是否可讀。
  • isWritable(Path path): 檢查文件是否可寫。
  • isExecutable(Path path): 檢查文件是否可執行。
  • size(Path path): 獲取文件大小(字節)。
  • getLastModifiedTime(Path path, LinkOption… options): 獲取文件最后修改時間。
  • readAttributes(Path path, class type, LinkOption… options): 讀取文件屬性集。這個方法非常強大,可以獲取文件的各種詳細屬性,比如BasicFileAttributes。

4. 文件系統遍歷

對于需要處理整個目錄樹的場景,Files也提供了強大的流式API。

  • list(Path dir): 列出目錄下的直接子文件和子目錄,返回Stream
  • walk(Path start, int maxDepth, FileVisitOption… options): 深度優先遍歷目錄樹,返回Stream。可以指定遍歷深度和選項。
  • find(Path start, int maxDepth, BiPredicate matcher, FileVisitOption… options): 遍歷目錄樹,并根據提供的匹配器進行過濾,返回Stream

這些方法基本涵蓋了日常文件操作的絕大部分需求。我個人覺得,熟練掌握這些,基本就能在Java里自如地玩轉文件系統了。

文件讀寫,Files有哪些更優雅的姿勢?

談到文件讀寫,特別是文本文件,Files類提供了幾種非常“Java 8”風格的優雅方式。我個人在處理一些配置文件或者日志分析時,特別偏愛用這些方法,它們能讓代碼看起來非常簡潔。

最直接的當然是上面提到的readAllLines(Path path, Charset cs)和write(Path path, Iterable extends CharSequence> lines, Charset cs, OpenOption… options)。比如,你想讀取一個UTF-8編碼的文件,然后把其中包含特定字符串的行篩選出來,再寫入另一個文件:

Path source = Paths.get("input.txt"); Path target = Paths.get("output.txt"); Charset utf8 = StandardCharsets.UTF_8;  try {     List<String> filteredLines = Files.readAllLines(source, utf8)                                     .stream()                                     .filter(line -> line.contains("important_keyword"))                                     .collect(Collectors.toList());      Files.write(target, filteredLines, utf8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);     System.out.println("Filtered lines written to " + target); } catch (IOException e) {     System.err.println("Error processing file: " + e.getMessage()); }

這段代碼,從讀取到過濾再到寫入,一氣呵成,沒有冗余的BufferedReader、BufferedWriter的創建和關閉,內部都幫你處理好了。但這里有個需要注意的點:readAllLines會一次性把所有內容加載到內存。對于特別大的文件(比如幾個GB),這樣做可能會導致內存溢出。

這時候,Files.lines(Path path, Charset cs)就派上用場了。它返回一個Stream,是惰性加載的,只有當你真正消費這個流的時候,才會去讀取文件內容。這對于處理大文件來說,是更內存友好的選擇。

Path largeFile = Paths.get("large_log.txt"); Path errorLog = Paths.get("error_log.txt");  try (Stream<String> lines = Files.lines(largeFile, utf8)) {     List<String> errorLines = lines.filter(line -> line.contains("ERROR"))                                    .limit(100) // 比如只取前100條錯誤                                    .collect(Collectors.toList());     Files.write(errorLog, errorLines, utf8);     System.out.println("Extracted error lines to " + errorLog); } catch (IOException e) {     System.err.println("Error reading large file: " + e.getMessage()); }

看到沒,try-with-resources配合Files.lines,既保證了資源自動關閉,又提供了流式處理的能力,簡直是完美組合。我個人覺得,這種方式才是真正意義上的“優雅”,它不僅讓代碼簡潔,更重要的是,它考慮到了性能和資源管理。

路徑操作與文件屬性:Files如何幫助我們更好地管理文件系統?

文件系統管理,不僅僅是創建刪除那么簡單,更多時候我們需要了解文件的“身份信息”——它的類型、大小、修改時間,甚至更底層的權限信息。Files類在這方面提供了非常細致且強大的支持,遠超java.io.File。

首先,一切都圍繞著Path對象展開。Path是NIO.2中表示文件或目錄路徑的核心抽象,你可以用Paths.get(“some/path/to/file.txt”)來創建它。有了Path,Files類的各種方法才能施展拳腳。

例如,我們想檢查一個路徑到底是個文件還是目錄,或者它是否存在:

Path myPath = Paths.get("/tmp/mydata"); // 假設這個路徑可能存在也可能不存在,可能是文件也可能是目錄  if (Files.exists(myPath)) {     System.out.println(myPath + " exists.");     if (Files.isDirectory(myPath)) {         System.out.println(myPath + " is a directory.");     } else if (Files.isRegularFile(myPath)) {         System.out.println(myPath + " is a regular file.");         try {             System.out.println("Size: " + Files.size(myPath) + " bytes.");             System.out.println("Last Modified: " + Files.getLastModifiedTime(myPath));         } catch (IOException e) {             System.err.println("Could not get file info: " + e.getMessage());         }     } } else {     System.out.println(myPath + " does not exist."); }

這些方法簡單直觀,但真正強大的在于readAttributes。當你需要獲取文件的一組屬性時,比如創建時間、最后訪問時間、文件所有者等,readAttributes就能派上用場。它返回一個實現了BasicFileAttributes接口的對象,或者更具體的屬性集接口,比如DosFileAttributes(針對windows系統)或PosixFileAttributes(針對unix/linux系統)。

Path someFile = Paths.get("important_document.pdf"); try {     BasicFileAttributes attrs = Files.readAttributes(someFile, BasicFileAttributes.class);     System.out.println("Is directory? " + attrs.isDirectory());     System.out.println("Is regular file? " + attrs.isRegularFile());     System.out.println("File size: " + attrs.size() + " bytes");     System.out.println("Creation time: " + attrs.creationTime());     System.out.println("Last Access time: " + attrs.lastAccessTime());     System.out.println("Last modified time: " + attrs.lastModifiedTime()); } catch (IOException e) {     System.err.println("Error reading attributes: " + e.getMessage()); }

這種方式比你一個個調用size()、getLastModifiedTime()要高效,因為它通常一次性從文件系統讀取所有請求的屬性。在需要批量獲取文件信息時,這能顯著減少與文件系統的交互次數,提升性能。我個人在做文件同步或者備份工具的時候,就經常用到這些屬性查詢方法,它們是判斷文件是否需要處理的重要依據。

遍歷文件系統,Files提供了哪些高級玩法?

遍歷文件系統,這可是個大活兒,尤其是當你需要處理一個復雜的目錄結構時。在Java NIO.2之前,我們通常需要自己寫遞歸函數來遍歷,既繁瑣又容易出錯。Files類徹底改變了這一點,它引入了流式API來簡化文件系統遍歷,讓這個過程變得異常優雅和高效。

最常用的三個方法是list()、walk()和find()。

  • Files.list(Path dir): 這個方法非常直接,它只列出指定目錄下的直接子文件和子目錄,不進行遞歸。返回的是一個Stream。這就像你打開一個文件夾,看到里面有什么,僅此而已。

    Path currentDir = Paths.get("."); // 當前目錄 try (Stream<Path> entries = Files.list(currentDir)) {     entries.forEach(System.out::println); } catch (IOException e) {     System.err.println("Error listing directory: " + e.getMessage()); }

    這個用法很像ls命令,簡單明了。

  • Files.walk(Path start, int maxDepth, FileVisitOption… options): 這才是真正的“大殺器”,它能遞歸地遍歷從start路徑開始的整個目錄樹。你可以指定maxDepth來限制遍歷的深度,比如1就和list差不多了,Integer.MAX_VALUE就是遍歷所有子目錄。它也返回一個Stream,包含了遍歷到的所有文件和目錄。

    我第一次用Files.walk的時候,簡直驚呆了,以前需要寫一遞歸邏輯才能實現的功能,現在幾行代碼就能搞定,效率提升不是一點半點。比如,你想找出某個目錄下所有.java文件:

    Path projectRoot = Paths.get("/path/to/my/java/project"); try (Stream<Path> javaFiles = Files.walk(projectRoot)) {     javaFiles.filter(Files::isRegularFile) // 確保是文件              .filter(p -> p.toString().endsWith(".java")) // 過濾出.java文件              .forEach(System.out::println); } catch (IOException e) {     System.err.println("Error walking directory: " + e.getMessage()); }

    這里,Files.walk返回的流包含了目錄和文件,所以我們通常會用Files::isRegularFile先過濾一下。

  • Files.find(Path start, int maxDepth, BiPredicate matcher, FileVisitOption… options): find比walk更進一步,它在遍歷的同時,允許你提供一個BiPredicate(一個接受Path和BasicFileAttributes的函數),直接在遍歷過程中進行過濾。這對于需要根據文件屬性(如大小、修改時間)來查找文件時非常有用。

    比如,查找所有大小超過1MB,且在過去24小時內修改過的PDF文件:

    Path searchDir = Paths.get("/path/to/documents"); long oneDayAgo = System.currentTimeMillis() - (24 * 60 * 60 * 1000);  try (Stream<Path> foundFiles = Files.find(searchDir, Integer.MAX_VALUE,         (path, attrs) -> attrs.isRegularFile() &&                          attrs.size() > (1024 * 1024) && // 1MB                          attrs.lastModifiedTime().toMillis() > oneDayAgo &&                          path.toString().endsWith(".pdf"))) {     foundFiles.forEach(System.out::println); } catch (IOException e) {     System.err.println("Error finding files: " + e.getMessage()); }

    find的強大之處在于,它將遍歷和過濾邏輯緊密結合,代碼更緊湊,也更易讀。在使用這些流時,記得使用try-with-resources來確保流的正確關閉,避免資源泄露,這在處理文件系統資源時尤為重要。這些高級遍歷方法,無疑讓Java在文件系統操作方面達到了一個新的高度,用起來真是得心應手。

? 版權聲明
THE END
喜歡就支持一下吧
點贊12 分享