“嗨!在今天的課程中,我們將繼續討論 Java 中的輸入和輸出流 ( Java I/O )。這不是關於該主題的第一課,當然也不會是最後一課 :)
因為它碰巧,Java 語言提供了很多處理 I/O 的方法。有相當多的類實現了這個功能,所以我們把它們分成幾節課——所以你不會從一開始就感到困惑 :) 過去課程,我們談到了
這是使用以下方法從文件中讀取數據的樣子

BufferedReader
,以及抽像類InputStream
和OutputStream
幾個後代。今天我們將考慮 3 個新類:FileInputStream
、 FileOutputStream
和 BufferedInputStream
。
文件輸出流類
該類的主要目的FileOutputStream
是將字節寫入文件。 沒什麼複雜的:)FileOutputStream
是抽像類的實現之一OutputStream
。在構造函數中,此類的對象採用目標文件(應寫入字節的位置)的路徑或對象File
。我們將檢查每個示例:
public class Main {
public static void main(String[] args) throws IOException {
File file = new File("C:\\Users\\Username\\Desktop\\test.txt");
FileOutputStream fileOutputStream = new FileOutputStream(file);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
創建File
對象時,我們將所需的路徑傳遞給構造函數。我們不需要提前創建它:如果它不存在,程序會創建它。您也可以在不創建額外對象的情況下通過,只需傳遞一個帶有路徑的字符串:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt");
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
兩種情況下的結果都是一樣的。 我們可以打開我們的文件並在那裡看到以下內容:
Hi! Welcome to CodeGym — The best site for would-be programmers!
但這裡有一個細微差別。嘗試連續多次運行上述示例中的代碼。然後查看文件並回答這個問題:它有多少行?只有一個。但是你多次運行代碼。事實證明,數據每次都被覆蓋——舊的被新的取代。如果這不適合我們並且我們需要按順序寫入文件,我們該怎麼辦?如果我們想連續三次將問候語寫入文件怎麼辦?這一切都非常簡單。由於語言無法知道我們在每種情況下需要什麼行為,FileOutputStream
構造函數可以採用一個額外的參數——boolean append
. 如果它的值為真,數據將被寫入文件的末尾。如果為 false(默認情況下為 false),任何舊數據都將被刪除並由新數據替換。讓我們通過運行修改後的代碼三次來檢查這一點:
public class Main {
public static void main(String[] args) throws IOException {
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt", true);
String greetings = "Hi! Welcome to CodeGym — The best site for would-be programmers!\r\n";
fileOutputStream.write(greetings.getBytes());
fileOutputStream.close();
}
}
文件內容:
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
Hi! Welcome to CodeGym — The best site for would-be programmers!
現在不一樣了!在使用 I/O 類時不要忘記這個特性。曾經有一段時間,我在任務上花費了數小時,絞盡腦汁數小時,試圖了解我的數據是如何從文件中消失的:)當然,就像其他 I/O 類一樣,不要忘記使用該close()
方法釋放資源。
文件輸入流類
有FileInputStream
相反的目的——從文件中讀取字節。正如FileOutputStream
inherits一樣OutputStream
,這個類派生自InputStream
抽像類。我們將在我們的“ test.txt ”文件中寫入幾行文本:
"So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters"

FileInputStream
:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
int i;
while((i=fileInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
我們從文件中讀取一個字節,將讀取的字節轉換為字符並顯示在控制台上。這是控制台輸出:
So close no matter how far
Couldn't be much more from the heart
Forever trusting who we are
And nothing else matters
緩衝輸入流類
我認為,鑑於過去課程中的知識,您可以很容易地說出我們為什麼需要這個BufferedInputStream
類以及它與FileInputStream
:) 相比有什麼優勢:) 我們已經遇到過緩衝流,所以在繼續閱讀之前嘗試猜測(或記住):) 緩衝流主要用於優化 I/O。 訪問數據源,例如從文件中讀取,在性能方面是一項昂貴的操作,而訪問文件以讀取每個字節是一種浪費。這就是為什麼BufferedInputStream
不是一次一個字節地讀取數據,而是以塊為單位讀取數據,並將它們臨時存儲在一個特殊的緩衝區中。這讓我們可以通過減少訪問文件的次數來優化程序。讓我們看看這是什麼樣子的:
public class Main {
public static void main(String[] args) throws IOException {
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\test.txt");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream, 200);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
}
}
這裡我們創建了一個BufferedInputStream
對象。InputStream
它的構造函數採用該類或其任何後代的實例,所以FileInputStream
會這樣做。 作為附加參數,它採用以字節為單位的緩衝區大小。由於這個參數,現在將從文件中讀取的數據不是一次一個字節,而是一次 200 個字節!想像一下我們減少了多少文件訪問次數。FileInputStream
要比較性能,您可以獲取一個大文本文件(幾兆字節的文本)並使用和比較讀取和輸出到控制台所花費的時間(以毫秒為單位)BufferedInputStream
。下面是演示這兩個選項的代碼:
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\textBook.rtf");
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
int i;
while((i = bufferedInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
public class Main {
public static void main(String[] args) throws IOException {
Date date = new Date();
FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Username\\Desktop\\26951280.rtf");
int i;
while((i = fileInputStream.read())!= -1){
System.out.print((char)i);
}
Date date1 = new Date();
System.out.println((date1.getTime() - date.getTime()));
}
}
在我的計算機上讀取一個 1.5 MB 的文件時,FileInputStream
在 ~3500 毫秒內完成了工作,但BufferedInputStream
在 ~1700 毫秒內完成了它。如您所見,緩衝流優化了工作,將其減半!:) 我們將繼續研究 I/O 課程——待會見!
GO TO FULL VERSION