1.數據流
程序很少作為一個孤島存在。程序通常以某種方式與“外部世界”交互。這可以通過從鍵盤讀取數據、發送消息、從 Internet 下載頁面,或者相反,將文件上傳到遠程服務器來實現。
我們可以用一個詞來指代所有這些行為:程序與外界之間的數據交換。等等,這不僅僅是一個詞。
當然,數據交換本身可以分為接收數據和發送數據兩部分。例如,您使用Scanner
對像從鍵盤讀取數據——這就是接收數據。然後您使用命令在屏幕上顯示數據System.out.println()
——這就是發送數據。
在編程中,術語“流”用於描述數據交換。這個詞是從哪裡來的?
在現實生活中,你可以有一股水流,也可以有一股意識流。在編程中,我們有數據流。
流是一種多功能工具。它們允許程序從任何地方接收數據(輸入流)並向任何地方發送數據(輸出流)。因此,有兩種類型:
- 輸入流用於接收數據
- 輸出流用於發送數據
為了使流“有形”,Java 的創建者編寫了兩個類:InputStream
和OutputStream
.
該類InputStream
有一個read()
方法可以讓您從中讀取數據。該類OutputStream
有一個write()
方法可以讓你向它寫入數據。他們還有其他方法,但稍後會詳細介紹。
字節流
我們在談論什麼樣的數據?它採用什麼格式?換句話說,這些類支持哪些數據類型?
這些是通用類,因此它們支持最常見的數據類型 — byte
. AnOutputStream
可以寫入字節(和字節數組),而InputStream
對象可以讀取字節(或字節數組)。就是這樣——它們不支持任何其他數據類型。
因此,這些流也被稱為字節流。
流的一個特點是它們的數據只能按順序讀取(或寫入)。如果不讀取流之前的所有數據,就無法從流的中間讀取數據。
這就是通過類從鍵盤讀取數據的方式Scanner
:您逐行順序地從鍵盤讀取數據。我們讀一行,然後讀下一行,再讀下一行,依此類推。恰當地,讀取行的方法稱為nextLine()
。
將數據寫入 anOutputStream
也是順序發生的。一個很好的例子是控制台輸出。您輸出一行,然後是另一行。這是順序輸出。你不能輸出第一行,然後是第十行,然後是第二行。所有數據僅按順序寫入輸出流。
字符流
您最近了解到字符串是第二流行的數據類型,而且確實如此。許多信息以字符和整個字符串的形式傳遞。計算機擅長以字節形式發送和接收所有內容,但人類並不是那麼完美。
考慮到這一事實,Java 程序員編寫了另外兩個類:Reader
和Writer
. 該類Reader
與類類似InputStream
,但其read()
方法讀取的不是字節,而是字符 ( char
)。班級Writer
對應班級OutputStream
。就像Reader
類一樣,它適用於字符 ( char
),而不是字節。
如果我們比較這四個類,我們會得到下圖:
字節(字節) | 字符(字符) | |
---|---|---|
讀取數據 |
|
|
寫入數據 |
|
|
實際應用
、和類本身不被任何人直接使用,因為它們不與InputStream
任何可從中讀取數據(或可寫入數據)的具體對象相關聯。但是這四個類有很多可以做很多事情的後代類。OutputStream
Reader
Writer
2.InputStream
類
該類InputStream
很有趣,因為它是數百個後代類的父類。它自己沒有任何數據,但它有所有派生類都繼承的方法。
一般情況下,流對像很少在內部存儲數據。流是讀取/寫入數據的工具,但不是存儲。也就是說,也有例外。
InputStream
該類及其所有子類的方法:
方法 | 描述 |
---|---|
|
從流中讀取一個字節 |
|
從流中讀取字節數組 |
|
從流中讀取所有字節 |
|
跳過n 流中的字節(讀取並丟棄它們) |
|
檢查流中剩餘的字節數 |
|
關閉流 |
讓我們簡要介紹一下這些方法:
read()
方法
該方法從流中read()
讀取一個字節並將其返回。您可能會對返回類型感到困惑int
。選擇此類型是因為它int
是標準整數類型。的前三個字節int
將為零。
read(byte[] buffer)
方法
這是該方法的第二個變體read()
。InputStream
它允許您一次從 all 中讀取一個字節數組。將存儲字節的數組必須作為參數傳遞。該方法返回一個數字——實際讀取的字節數。
假設您有一個 10 KB 的緩衝區,並且您正在使用該類從文件中讀取數據FileInputStream
。如果文件僅包含 2 KB,則所有數據都將加載到緩衝區數組中,並且該方法將返回數字 2048(2 KB)。
readAllBytes()
方法
一個很好的方法。它只是從中讀取所有數據,InputStream
直到用完並將其作為單字節數組返回。這對於讀取小文件非常方便。大文件在物理上可能不適合內存,並且該方法將拋出異常。
skip(long n)
方法
此方法允許您跳過對象的前 n 個字節InputStream
。因為數據是嚴格按順序讀取的,所以此方法只是從流中讀取前 n 個字節並將其丟棄。
返回實際跳過的字節數(如果流在n
跳過字節之前結束)。
int available()
方法
該方法返回流中剩餘的字節數
void close()
方法
該close()
方法關閉數據流並釋放與之關聯的外部資源。一旦流關閉,就不能再從中讀取數據。
讓我們編寫一個示例程序來複製一個非常大的文件。我們不能使用該readAllBytes()
方法將整個文件讀入內存。例子:
代碼 | 筆記 |
---|---|
|
InputStream 用於從文件中讀取OutputStream 用於寫入文件 將數據讀入的緩衝區 只要流中有數據 將數據讀入緩衝區 將緩衝區中的數據寫入第二個流 |
在此示例中,我們使用了兩個類:是用於從文件讀取數據FileInputStream
的後代,以及用於將數據寫入文件的後代。稍後我們將討論第二類。InputStream
FileOutputStream
OutputStream
這裡另一個有趣的點是real
變量。當從文件中讀取最後一個數據塊時,它的數據量很可能少於 64KB。因此,我們需要輸出的不是整個緩衝區,而是其中的一部分——第一個real
字節。這正是write()
方法中發生的事情。
3.Reader
類
該類Reader
是該類的完整類比InputStream
。唯一的區別是它使用字符 ( char
),而不是字節。就像InputStream
類一樣,Reader
類本身不會在任何地方使用:它是數百個子類的父類,並為所有子類定義通用方法。
Reader
該類(及其所有後代類)的方法:
方法 | 描述 |
---|---|
|
char 從流中讀取一個 |
|
char 從流中讀取數組 |
|
跳過n chars 流(讀取並丟棄它們) |
|
檢查流中是否還有剩餘的東西 |
|
關閉流 |
這些方法與類中的方法非常相似InputStream
,儘管存在細微差別。
int read()
方法
此方法char
從流中讀取一個並返回它。類型char
擴展為int
,但結果的前兩個字節始終為零。
int read(char[] buffer)
方法
這是該方法的第二個變體read()
。Reader
它使您可以一次從 a 中讀取一個 char 數組。將存儲字符的數組必須作為參數傳遞。該方法返回一個數字——實際讀取的字符數。
skip(long n)
方法
此方法允許您跳過對象的前 n 個字符Reader
。它的工作原理與類的類似方法完全相同InputStream
。返回實際跳過的字符數。
boolean ready()
方法
true
如果流中有未讀字節則返回。
void close()
方法
該close()
方法關閉數據流並釋放與之關聯的外部資源。一旦流關閉,就不能再從中讀取數據。
為了比較,讓我們編寫一個複製文本文件的程序:
代碼 | 筆記 |
---|---|
|
Reader 用於從文件中Writer 讀取 用於寫入文件我們將讀取數據的緩衝區 只要流中有數據 將數據讀入緩衝區 將緩衝區中的數據寫入第二個流 |
GO TO FULL VERSION