Java 中 getResourceAsStream() 和 FileInputStream 指南
1. 概述
在本教程中,我們將探討 Java 中讀取檔案的不同方法之間的差異。我們將比較getResourceAsStream()
方法和FileInputStream
類別並討論它們的用例。我們還將討論Files.newInputStream()
方法,由於其記憶體和效能優勢,建議使用FileInputStream
方法。
然後我們將查看程式碼範例以了解如何使用這些方法讀取檔案。
2. 基礎知識
在深入研究程式碼範例之前,讓我們先了解getResourceAsStream()
和FileInputStream
之間的差異以及它們的流行用例。
2.1.使用getResourceAsStream()
讀取文件
getResourceAsStream()
方法從類別路徑讀取檔案。傳遞給getResourceAsStream()
方法的檔案路徑應該相對於 classpath 。此方法傳回一個可用於讀取檔案的InputStream
。
此方法通常用於讀取設定檔、屬性檔以及與應用程式一起打包的其他資源。
2.2.使用FileInputStream
讀取文件
另一方面, FileInputStream
類別用於從檔案系統讀取檔案。當我們需要讀取未與應用程式一起打包的檔案時,這非常有用。
傳遞給FileInputStream
建構函數的檔案路徑應該是絕對路徑或相對於目前工作目錄的路徑。
由於使用了終結器, FileInputStream
物件可能會出現記憶體和效能問題。 FileInputStream
的更好替代方法是Files.newInputStream()
方法,其運作方式相同。我們將在程式碼範例中使用Files.newInputStream()
方法從檔案系統讀取檔案。
這些方法通常用於讀取檔案系統外部存在的文件,例如日誌檔案、使用者資料檔案和機密檔案。
3. 程式碼範例
讓我們來看一個範例來示範getResourceAsStream()
和Files.newInputStream()
的用法。我們將創建一個簡單的實用程式類,它使用這兩種方法讀取檔案。然後我們將透過從類別路徑和檔案系統讀取範例檔案來測試這些方法。
3.1.使用getResourceAsStream()
首先,我們來看看getResourceAsStream()
方法的用法。我們將建立一個名為FileIOUtil
的類,並新增一個從資源中讀取檔案的方法:
`static String readFileFromResource(String filePath) {
try (InputStream inputStream = FileIOUtil.class.getResourceAsStream(filePath)) {
String result = null;
if (inputStream != null) {
result = new BufferedReader(new InputStreamReader(inputStream))
.lines()
.collect(Collectors.joining("\n"));
}
return result;
} catch (IOException e) {
LOG.error("Error reading file:", e);
return null;
}
}`
在此方法中,我們透過將檔案的路徑作為參數傳遞給getResourceAsStream()
方法來取得InputStream
。該檔案路徑應該相對於類別路徑。然後我們使用BufferedReader
讀取文件的內容。此方法逐行讀取內容並使用Collectors.joining()
方法將它們連接起來。最後,我們將文件的內容作為String
回傳。
如果出現異常,例如找不到文件,我們會捕獲異常並傳回null
。
3.2.使用Files.newInputStream()
接下來,讓我們使用Files.newInputStream()
方法定義一個類似的方法:
`static String readFileFromFileSystem(String filePath) {
try (InputStream inputStream = Files.newInputStream(Paths.get(filePath))) {
return new BufferedReader(new InputStreamReader(inputStream))
.lines()
.collect(Collectors.joining("\n"));
} catch (IOException e) {
LOG.error("Error reading file:", e);
return null;
}
}`
在此方法中,我們使用Files.newInputStream()
方法從檔案系統讀取檔案。檔案路徑應該是絕對路徑或相對於專案目錄的路徑。與先前的方法類似,我們讀取並傳回文件的內容。
4. 測試
現在,讓我們透過讀取範例文件來測試這兩種方法。我們將觀察在資源文件和外部文件的情況下文件路徑如何傳遞給方法。
4.1.從類別路徑讀取文件
首先,我們將比較這些方法如何從類別路徑讀取檔案。讓我們在src/main/resources
目錄下建立一個名為test.txt
的文件,並在其中加入一些內容:
`Hello!
Welcome to the world of Java NIO.`
我們將使用這兩種方法讀取該文件並驗證內容:
`@Test
void givenFileUnderResources_whenReadFileFromResource_thenSuccess() {
String result = FileIOUtil.readFileFromResource("/test.txt");
assertNotNull(result);
assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}
@Test
void givenFileUnderResources_whenReadFileFromFileSystem_thenSuccess() {
String result = FileIOUtil.readFileFromFileSystem("src/test/resources/test.txt");
assertNotNull(result);
assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}`
正如我們所看到的,這兩種方法都會讀取檔案test.txt
並傳回其內容。然後我們比較內容以確保它們符合預期值。兩種方法之間的差異在於我們作為參數傳遞的檔案路徑。
readFileFromResource()
方法需要一個相對於類別路徑的路徑。由於該檔案直接位於src/main/resources
目錄下,因此我們傳遞/test.txt
作為檔案路徑。
另一方面, readFileFromFileSystem()
方法需要絕對路徑或相對於目前工作目錄的路徑。我們傳遞src/main/resources/test.txt
作為檔案路徑。或者,我們可以傳遞檔案的絕對路徑,例如/path/to/project/src/main/resources/test.txt
。
4.2.從檔案系統讀取文件
接下來,讓我們測試這些方法如何從檔案系統讀取檔案。我們將在專案目錄外建立一個名為external.txt
的文件,並嘗試使用這兩種方法讀取該文件。
讓我們建立測試方法來使用這兩種方法讀取檔案:
`@Test
void givenFileOutsideResources_whenReadFileFromFileSystem_thenSuccess() {
String result = FileIOUtil.readFileFromFileSystem("../external.txt");
assertNotNull(result);
assertEquals(result, "Hello!\n" + "Welcome to the world of Java NIO.");
}
@Test
void givenFileOutsideResources_whenReadFileFromResource_thenNull() {
String result = FileIOUtil.readFileFromResource("../external.txt");
assertNull(result);
}`
在這裡,我們傳遞external.txt
檔案的相對路徑。 readFileFromFileSystem()
方法直接從檔案系統讀取檔案並傳回其內容。
如果我們嘗試使用readFileFromResource()
方法讀取文件,它將傳回null
因為該文件位於類別路徑之外。
5. 結論
在本文中,我們探討了使用getResourceAsStream()
從類別路徑讀取檔案和使用Files.newInputStream()
從檔案系統讀取檔案之間的差異。我們討論了這兩種方法的用例和行為,並查看了演示其用法的範例。
與往常一樣,程式碼範例可在 GitHub 上取得。