nio 读取目录所有文件_在NIO.2中使用文件和目录
nio 讀取目錄所有文件
在先前的文章中,我討論了文件和目錄的創建( 創建文件和目錄 )以及選擇( 列出和過濾目錄內容 )。 采取的最后一個合乎邏輯的步驟是探索我們如何使用它們以及如何使用它們。 這是庫的一部分,已進行了很大的重新設計。 這方面的更新包括保證某些操作的原子性,API改進,性能優化以及引入適當的異常層次結構,這些層次結構取代了IO庫以前版本中的boolean返回方法。
開啟檔案
在開始閱讀和寫入文件之前,我們需要介紹這些操作的一個共同基礎-文件的打開方式。 文件的打開方式直接影響這些操作的結果及其性能。 讓我們看一下打開枚舉java.nio.file.StandardOpenOption包含的文件的標準選項:
| APPEND | 如果打開文件以進行WRITE訪問,則字節將被寫入文件的末尾而不是開始。 |
| CREATE | 如果不存在,請創建一個新文件。 |
| CREATE_NEW | 創建一個新文件,如果文件已經存在則失敗。 |
| DELETE_ON_CLOSE | 關閉刪除。 |
| DSYNC | 要求對文件內容的每次更新都同步寫入基礎存儲設備。 |
| READ | 打開以進行讀取訪問。 |
| SPARSE | 稀疏文件。 |
| SYNC | 要求對文件內容或元數據的每次更新都同步寫入基礎存儲設備。 |
| TRUNCATE_EXISTING | 如果該文件已經存在并且已打開以進行WRITE訪問,則其長度將被截斷為0。 |
| WRITE | 打開以進行寫訪問。 |
這些都是開發人員您可能需要正確處理文件打開(無論是讀取還是寫入)的所有標準選項。
讀取文件
在讀取文件時,NIO.2提供了幾種方法-每種都有其優缺點。 這些方法如下:
- 將文件讀入字節數組
- 使用無緩沖流
- 使用緩沖流
讓我們來看看第一個選項。 類Files提供了方法readAllBytes來做到這一點。 將文件讀入字節數組似乎很簡單,但這可能僅適用于非常有限的文件范圍。 由于我們將整個文件放入內存中,因此必須注意該文件的大小。 僅當我們嘗試讀取小文件并且可以立即完成時,使用此方法才是合理的。 如以下代碼段所示,這是非常簡單的操作:
Path filePath = Paths.get("C:", "a.txt");if (Files.exists(filePath)) {try {byte[] bytes = Files.readAllBytes(filePath);String text = new String(bytes, StandardCharsets.UTF_8);System.out.println(text);} catch (IOException e) {throw new RuntimeException(e);} }上面的代碼首先將文件讀取到字節數組中,然后使用以下輸出構造包含該文件內容的字符串對象:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet justo nec leo euismod porttitor. Vestibulum id sagittis nulla, eu posuere sem. Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.當我們需要以字符串形式讀取文件的內容時,可以使用上面的代碼。 但是,這種解決方案不是很干凈,我們可以使用類Files readAllLines來避免這種尷尬的構造。 當需要逐行讀取人類可讀的輸出時,此方法可作為讀取文件的便捷解決方案。 此方法的使用再次非常簡單,并且與前面的示例非常相似(有相同的限制):
Path filePath = Paths.get("C:", "b.txt");if (Files.exists(filePath)) {try {List<String> lines = Files.readAllLines(filePath, StandardCharsets.UTF_8);for (String line : lines) {System.out.println(line);}} catch (IOException e) {throw new RuntimeException(e);} }具有以下輸出:
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam sit amet justo nec leo euismod porttitor. Vestibulum id sagittis nulla, eu posuere sem. Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.使用流讀取文件
繼續使用更復雜的方法,我們總是可以使用良好的舊流,就像我們以前使用該庫的先前版本一樣。 由于這是眾所周知的基礎,因此我將僅展示如何獲取這些流的實例。 首先,我們可以通過調用newInputStream方法從類Files檢索InputStream實例。 像往常一樣,可以進一步使用裝飾器模式,并從中輸出緩沖流。 為了方便起見,請使用newBufferedReader方法。 這兩個方法都返回一個流實例,該實例是普通的舊java.io對象。
Path filePath1 = Paths.get("C:", "a.txt"); Path filePath2 = Paths.get("C:", "b.txt");InputStream is = Files.newInputStream(filePath1); InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr);BufferedReader reader = Files.newBufferedReader(filePath2, StandardCharsets.UTF_8);寫入文件
寫入文件與NIO.2庫提供的一系列工具中的讀取過程相似,因此只需回顧一下:
- 將字節數組寫入文件
- 使用無緩沖流
- 使用緩沖流
再次讓我們首先探索字節數組選項。 毫不奇怪, Files類支持兩種方法write 。 我們正在從數組或文本行中寫入字節,在這里我們需要關注StandardOpenOptions ,因為這兩種方法都可能受到這些修飾符的自定義選擇的影響。 默認情況下,如果沒有將StandardOpenOption傳遞給該方法,則write方法的行為就像存在CREATE , TRUNCATE_EXISTING和WRITE選項一樣(如Javadoc中所述)。 話雖如此,請注意不要使用默認(無打開選項)版本的write方法,因為它要么創建一個新文件,要么最初將現有文件截斷為零大小。 寫入完成后,文件會自動關閉-成功寫入后會引發異常。 對于文件大小,適用與readAllBytes相同的限制。
下面的示例演示如何將字節數組寫入文件。 請注意,由于write方法的默認行為,因此沒有任何檢查方法。 該示例可以多次運行,并具有兩個不同的結果。 第一次運行將創建一個文件,打開該文件進行寫入,然后將數組bytes寫入此文件。 此代碼的任何后續調用都將擦除文件,并將bytes數組的內容寫入此空文件。 兩次運行都將導致文本為“ Hello world!”的封閉文件。 寫在第一行。
Path newFilePath = Paths.get("/home/jstas/a.txt"); byte[] bytes = new byte[] {0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x21};try {Files.write(newFilePath, bytes); } catch(IOException e) {throw new RuntimeException(e); }當我們需要寫行而不是字節時,我們可以將字符串轉換為字節數組,但是,還有一種更方便的方法。 只需準備一行列表,然后將其傳遞給write方法即可。 請注意以下示例中兩個StandardOpenOption的使用。 通過使用這些選項,我可以確保存在一個文件(如果不存在,則會創建該文件),以及將數據追加到該文件的方式(因此不會丟失任何先前寫入的數據)。 整個例子很簡單,看一下:
Path filePath = Paths.get("/home/jstas/b.txt");List<String> lines = new ArrayList<>(); lines.add("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); lines.add("Aliquam sit amet justo nec leo euismod porttitor."); lines.add("Vestibulum id sagittis nulla, eu posuere sem."); lines.add("Cras commodo, massa sed semper elementum, ligula orci malesuada tortor, sed iaculis ligula ligula et ipsum.");try {Files.write(filePath, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND); } catch (IOException e) {throw new RuntimeException(e); }使用流寫入文件
對于較大的文件,使用字節數組可能不是一個好主意。 這是流進入的時間。類似于閱讀本章,我將不解釋流或如何使用它們。 我寧愿專注于檢索其實例的方法。 類Files提供了newOutputStream方法,該方法接受StandardOpenOption來自定義流行為。 默認情況下,當沒有將StandardOpenOption傳遞給該方法時,流write方法的行為就像存在CREATE , TRUNCATE_EXISTING和WRITE選項一樣(如Javadoc中所述)。 該流沒有被緩沖,但是通過一點裝飾器魔術,您可以創建BufferedWriter實例。 為了解決這種不便,NIO.2附帶了newBufferWriter方法,該方法可以立即創建緩沖流實例。 以下代碼段顯示了兩種方式:
Path filePath1 = Paths.get("/home/jstas/c.txt"); Path filePath2 = Paths.get("/home/jstas/d.txt");OutputStream os = Files.newOutputStream(filePath1); OutputStreamWriter osw = new OutputStreamWriter(os); BufferedWriter bw = new BufferedWriter(osw);BufferedWriter writer = Files.newBufferedWriter(filePath2, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.APPEND);復制和移動文件和目錄
復制文件和目錄
NIO.2最受歡迎的功能之一是更新了處理復制和移動文件和目錄的方式。 為了使所有內容保持一致,設計人員決定在新文件系統API中引入兩個父(標記)接口: OpenOption和CopyOption (包java.nio.file兩個接口)。 上一章提到的StandardOpenOption枚舉實現了OpenOption接口。 CopyOption接口有兩個實現,其中一個已經在關于NIO.2中的Links的帖子中見過。 你們中有些人可能還記得LinkOption枚舉,它被稱為實現指導方法,用于處理鏈接相關的操作。 但是,還有另一種實現–包java.nio.file StandardCopyOption枚舉。 再次,我們將看到另一個枚舉–用于指導復制操作。 因此,在深入研究任何代碼之前,讓我們回顧一下使用不同的復制選項可以實現的目標。
| ATOMIC_MOVE | 將文件作為原子文件系統操作移動。 |
| COPY_ATTRIBUTES | 將屬性復制到新文件。 |
| REPLACE_EXISTING | 替換現有文件(如果存在)。 |
使用這些選項來指導您的IO操作非常簡單,也很簡單。 由于我們正在嘗試復制文件,因此ATOMIC_MOVE使用意義不大(您仍然可以使用它,但最終會出現java.lang.UnsupportedOperationException: Unsupported copy option )。 類Files提供了三種copy方法,可用于不同目的:
- copy(InputStream in, Path target, CopyOption... options)
- 將所有字節從輸入流復制到文件。
- copy(Path source, OutputStream out)
- 將所有字節從文件復制到輸出流。
- copy(Path source, Path target, CopyOption... options)
- 將文件復制到目標文件。
在我們獲得任何代碼之前,我相信最好了解copy方法的最重要的行為功能(上述三個方法中的最后一個)。 copy方法的行為如下(基于Javadoc):
- 默認情況下,如果目標文件已經存在或為符號鏈接,則復制將失敗。
- 如果源和目標是同一文件,則該方法將完成而不復制該文件。 (有關更多信息,請查看類Files方法isSameFile )
- 不需要將文件屬性復制到目標文件。
- 如果源文件是目錄,則它將在目標位置創建一個空目錄(不復制目錄中的條目)。
- 復制文件不是原子操作。
- 自定義實現可能會帶來新的特定選項。
這些是copy方法內部工作的核心原理。 現在是查看代碼示例的好時機。 由于此方法非常易于使用,因此可以將其實際使用(使用最常見的copy方法形式)。 如預期的那樣,以下代碼將復制源文件(并可能覆蓋目標文件)并保留文件屬性:
Path source = Paths.get("/home/jstas/a.txt"); Path target = Paths.get("/home/jstas/A/a.txt");try {Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) {throw new RuntimeException(e); }這里沒有什么大的驚喜–代碼復制帶有文件屬性的源文件。 如果您覺得我忘記了(不是空的)目錄,請讓我向我保證。 也可以使用NIO.2復制,移動或刪除填充的目錄,但這是我將在下一篇文章中介紹的內容,因此您將不得不等待幾天。
移動文件和目錄
當涉及到移動文件時,我們再次需要能夠指定選項,以指導方法從Files類move的過程。 在這里,我們利用了上一章中提到的StandardCopyOptions 。 兩個相關的選項是ATOMIC_MOVE和REPLACE_EXISTING 。 首先,讓我們從一些基本特征入手,然后繼續進行代碼示例:
- 默認情況下,如果目標文件已存在,則move方法將失敗。
- 如果源和目標是同一文件,則該方法將完成而不移動文件。 (有關更多信息,請查看類Files方法isSameFile )
- 如果源是符號鏈接,則鏈接本身將被移動。
- 如果源文件是目錄,則必須為空才能移動。
- 不需要移動文件屬性。
- 可以將移動文件配置為原子操作,但不必這樣做。
- 自定義實現可能會帶來新的特定選項。
代碼非常簡單,因此讓我們看下面的代碼片段:
Path source = Paths.get("/home/jstas/b.txt"); Path target = Paths.get("/home/jstas/A/b.txt");try {Files.move(source, target, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING); } catch(IOException e) {throw new RuntimeException(e); }如預期的那樣,代碼以原子操作方式移動源文件。
刪除文件和目錄
本文的最后一部分致力于刪除文件和目錄。 再次刪除文件非常簡單,可以使用兩種可能的方法來調用(通常都從Files類):
- public static void delete(Path path)
- public static boolean deleteIfExists(Path path)
兩種方法使用相同的規則:
- 默認情況下,當文件是目錄并且不為空時,刪除方法將失敗,并顯示DirectoryNotEmptyException 。
- 如果文件是符號鏈接,則鏈接本身將被刪除。
- 刪除文件可能不是原子操作。
- 如果文件已打開或被JVM或其他軟件使用,則可能不會刪除文件。
- 自定義實現可能會帶來新的特定選項。
輸出:
Any file deleted: false翻譯自: https://www.javacodegeeks.com/2014/06/working-with-files-and-directories-in-nio-2.html
nio 讀取目錄所有文件
總結
以上是生活随笔為你收集整理的nio 读取目录所有文件_在NIO.2中使用文件和目录的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 磁铁是怎么做成的 磁铁做成的方法
- 下一篇: 禁止自建机房(自建机房如何防止DDOS)