Java 文件——流(Stream)的基本介紹

1. 流 Stream

Java中(絕大部分編程語言類似)文件一般不是單獨(dú)處理芬膝,而是視為輸入輸出(I/O)設(shè)備的一種。
Java使用統(tǒng)一的概念來處理所有的IO菇晃。包括鍵盤祈远,終端呆万,網(wǎng)絡(luò)等。

  • JavaIO的基本類位于java.io包下车份。
Stream 含義
InputStream 表示輸入流
OutputStream 表示輸出流
FileInputStream 表示文件輸入流
FileOutputStream 表示文件輸出流

有了流的概念,就有了很多面向流的函數(shù)谋减,輸入輸出都是抽象的流,提供流的加密扫沼、壓縮等功能出爹。
一些實(shí)際上不是IO的數(shù)據(jù)源和目的地也轉(zhuǎn)換成了流,以便參與流的整體概念體系的協(xié)作充甚。
例如以政,字節(jié)數(shù)組ByteArrayInputStream/ByteArrayOutputStream

2. 裝飾器設(shè)計(jì)模式

基本的流按照字節(jié)讀寫霸褒,沒有緩沖區(qū)伴找,性能底下。Java使用裝飾器模式引入很多裝飾類對基本的流增加功能废菱。
一個(gè)裝飾類一般只關(guān)注一個(gè)方面的功能技矮。所以實(shí)際使用中經(jīng)常需要使用多個(gè)裝飾類抖誉。

Java中有很多裝飾類。對流提供過濾功能有兩個(gè)基類:FilterInputStream/FilterOutputSteam.
過濾功能的裝飾器對流提供一些功能包裝衰倦,輸入輸出都是流袒炉。
流的裝飾器類成對出現(xiàn),分別對應(yīng)輸入和輸出流樊零。
FilterInputStream/FilterOutputSteam有很多子類我磁,這里只列出出入的子類,輸出的子類類似:

FilterInputStream的子類 功能
BufferedInputStream 對流起緩沖作用
DataInputStream 按照8種基本類型對流讀寫
GZipInputStream 對流提供壓縮功能
ZipInputStream 對流提供壓縮功能
PrintStream 將基本類型驻襟,對象輸出為字符串表示

3. Reader/Writer

以InputStream/OutputStream 為基類的流基本都是以二進(jìn)制形式處理數(shù)據(jù)夺艰。
不能方便的處理文本文件,沒有編碼概念沉衣。能方便的按字符處理文本的基類是Reader/Writer郁副。

這兩個(gè)類也有很多子類。

Reader/Writer 的子類 功能
FileReader/FileWriter 讀/寫文件
BufferedReader/BufferedWriter 緩沖讀/寫
CharArrayReader/CharArrayWriter 將字符數(shù)組包裝成流
StringReader/StringWriter 將字符串包裝成流
InputStreamReader/InputStreamWriter 轉(zhuǎn)換InputStream/OutputStream和Reader/Writer
PrintWrite 輸出Write中的基本類型豌习,對象輸出為其字符串表示

大部分情況下存谎,使用流或者Reader/Writer讀寫文件內(nèi)容。但Java還提供樂一個(gè)獨(dú)立的可以隨機(jī)讀寫文件的類RandomAccessFile肥隆。用于大小已知的文件既荚。開發(fā)中用的較少。
一些系統(tǒng)程序中用的較多栋艳。

以上介紹的類都是操作數(shù)據(jù)本身固以,而數(shù)據(jù)保存的載體,Java使用File類來表示嘱巾,提供文件路徑憨琳,文件元數(shù)據(jù),臨時(shí)文件旬昭,權(quán)限管理等功能篙螟。

4. Nio

上面的類都是位于java.io包下,Java中還有一個(gè)關(guān)于IO的操作包java.nio,nio的意思是New IO问拘。
它有緩沖區(qū)和通道的概念遍略。

緩沖和通道概念更像是操作系統(tǒng)的概念。利用緩沖區(qū)和通道往往可以達(dá)成和流類似的目的骤坐,某些操作性能也更高绪杏,

例如:通道可以利用操作系統(tǒng)和硬件提供的DMA(direct memory access 直接內(nèi)存存取)機(jī)制直接將數(shù)據(jù)從硬盤復(fù)制到網(wǎng)卡(不需要程序和CPU的參與)。

NIO還支持一些比較底層的功能纽绍。如 內(nèi)存映射文件(常用)蕾久、文件加鎖、自定義文件系統(tǒng)拌夏、非阻塞式IO,異步IO等僧著。

5. Serialization/Deserialization 序列化 反序列化

Serialization 序列化:是指將內(nèi)存中的java對象持久的保存到一個(gè)流中履因。
Deserialization 反序列:是指將流中的對象恢復(fù)到j(luò)ava內(nèi)存。

一般有兩個(gè)用途:一個(gè)是對象持久化盹愚;另一個(gè)是網(wǎng)絡(luò)遠(yuǎn)程調(diào)用栅迄。

Java主要通過interface Serializable 和class ObjectInputStream/ObjectOutputStream提供對序列化的支持。

Java的默認(rèn)序列化有一些缺點(diǎn):序列化后的形式較大浪費(fèi)空間皆怕,序列化和反序列化的性能較低毅舆,java獨(dú)有的格式,不能與其他語言交互愈腾。

5.1 Xml/Json

Java對象可以序列化為xml格式,xml格式比較笨重朗兵,現(xiàn)在更多的使用Json格式。

XML/JSON都是文本格式顶滩,便于人閱讀余掖,但占用空間相對較大。在只用于網(wǎng)絡(luò)遠(yuǎn)程調(diào)用的情況下礁鲁,有很多其他的更高效的格式盐欺,比如ProtoBuf、Thrift,MessagePack.
其中仅醇,MessagePack是二進(jìn)制形式的JSON,更小更快冗美。

6. 二進(jìn)制文件和字節(jié)流

二進(jìn)制讀寫流的類的有:

類名 說明
InputStream/OutputStream 抽象基類
FileInputStream/FileOutputStream 輸入源和輸出目標(biāo)是文件的流
ByteArrayInputStream/ByteArrayOutputStream 輸入源和輸出目標(biāo)是字節(jié)數(shù)組的流
DataInputStream/DateOutputStream 裝飾類,按照基本類型和字符串而非是字節(jié)讀寫流
BufferedInputStream/BufferedOutputStream 裝飾類析二,對輸入輸出流提供緩沖功能

6.1 InputStream/OutputStream 抽象基類

先介紹InputStream

6.1.1 InputStream的主要方法是 public abstract int read() throw IOException粉洼。

該抽象方法的一般實(shí)現(xiàn)是從流中讀取下一個(gè)字節(jié),返回取值范圍是-1,0~255的int類型叶摄。
當(dāng)讀取到流的結(jié)尾時(shí)返回-1,如果流中沒有數(shù)據(jù)属韧,read()方法會阻塞知道數(shù)據(jù)到來、流關(guān)閉或異常出現(xiàn)蛤吓。

6.1.2 InputStream還有 public int read(byte b[]) throws IOException 方法宵喂,可以一次性讀取多個(gè)字節(jié)。

  • 讀入的字節(jié)放入?yún)?shù)數(shù)組b[]中会傲。返回讀入的實(shí)際字節(jié)個(gè)數(shù)锅棕。實(shí)際字節(jié)個(gè)數(shù)小于(流讀完了而沒有讀滿)等于數(shù)組b的長度。
    如果剛開始讀取就讀到末尾則返回-1淌山。否則該方法會盡力讀取至少一個(gè)字節(jié)裸燎,如果流中沒有字節(jié)則阻塞。

  • 非抽象方法泼疑,有默認(rèn)實(shí)現(xiàn):循環(huán)讀取一個(gè)字節(jié)的read方法德绿,但是子類的實(shí)現(xiàn)一邊更為高效。

  • 流讀取結(jié)束后都應(yīng)該調(diào)用close()方法關(guān)閉釋放資源。所以一般放入finally語句中脆炎。
    close()方法自身也可能拋出異常梅猿,但通趁ダ保可以捕獲并忽略秒裕。

6.1.3 InputStream中還定義了如下方法:

1. public long skip(long n) throws IOException
2. public int available() throws IOException
3. public synchronized void mark(int readlimit)
4. public boolean markSupported()
5. public synchronized void reset() throws IOException
  • skip(long n)方法跳過輸入流中的n個(gè)字節(jié),返回實(shí)際跳過的字節(jié)個(gè)數(shù)(流中剩余的字節(jié)個(gè)數(shù)可能小于n).
  • avaiable() 返回下一次不需要阻塞就能讀取到的大概字節(jié)個(gè)數(shù),一般用在從網(wǎng)絡(luò)讀取數(shù)據(jù)時(shí)等到有足夠數(shù)據(jù)才去讀钞啸,防止阻塞几蜻。

一般的流都是一次性讀取的,且只能按照輸出的這一個(gè)方向讀取体斩,但是有時(shí)候希望能夠先看下后面的內(nèi)容梭稚,根據(jù)情況再重新讀取。

比如處理一個(gè)未知的二進(jìn)制文件絮吵,不確定其類型弧烤,我們可能可以通過流的前幾十個(gè)字節(jié)判斷其類型。然后重置到流開頭蹬敲。交給相應(yīng)的代碼處理暇昂。

InputStream定義了三個(gè)方法,用于支持從讀過的流中重復(fù)讀劝槲恕:mark reset markSupported
具體步驟是

  1. 先使用 mark(int readlimit)將當(dāng)前位置標(biāo)記下來急波,readlimit表示往后可以讀取的最多字節(jié)數(shù)。讀取一些字節(jié)后(需要小于readlimit瘪校,否則標(biāo)記失效)澄暮。
  2. 調(diào)用reset()方法重置到mark標(biāo)記的位置,

不是所有的流都支持mark reset方法阱扬。是否支持可以通過調(diào)用markSupported方法查看返回值確認(rèn)泣懊。
InputStream 默認(rèn)實(shí)現(xiàn)是不支持的,F(xiàn)ileInputStream不支持麻惶,但BufferedInputStreamByteArrayInputStream支持嗅定。

接下來介紹 OutputStream

6.1.4 OutputStream的基本(主要)方法是 public abstract void write(int b) throws IOException
向六中寫入一個(gè)Byte字節(jié),參數(shù)雖然是int,但只會用到最低的8bit(1Byte=8bit).

6.1.5 OutputStream還有兩個(gè)批量寫入的方法

public void write(byte b[]) throws IOException
public void write(byte b[], int off, int len) throws IOException 

第二個(gè)方法用踩,第一個(gè)寫入的字節(jié)是b[off],寫入個(gè)數(shù)len,最后一個(gè)是b[off+len-1].

6.1.6 OutputStream還有兩個(gè)方法 flush close

public void flush() throws IOException
public void close() throws IOException

flush()方法只對有緩沖的流起作用渠退,其將流中緩沖而未實(shí)際寫入的數(shù)據(jù)進(jìn)行實(shí)際寫入。
比如在BufferedOutputStream中脐彩,調(diào)用flush方法會將其緩沖區(qū)的內(nèi)容寫到其裝飾的流中碎乃,并調(diào)用該流的flush方法。
基類OutputStream沒有緩沖惠奸,flush方法為空梅誓。
FileOutputStream沒有緩沖,沒有flush方法。

close()方法一般會先調(diào)用flush()方法梗掰,然后再釋放占用的資源嵌言。
InputOutStream一樣,close()方法應(yīng)該放在finally塊中及穗。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末摧茴,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子埂陆,更是在濱河造成了極大的恐慌苛白,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焚虱,死亡現(xiàn)場離奇詭異购裙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)鹃栽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進(jìn)店門躏率,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人民鼓,你說我怎么就攤上這事薇芝。” “怎么了摹察?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵恩掷,是天一觀的道長。 經(jīng)常有香客問我供嚎,道長黄娘,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任克滴,我火速辦了婚禮逼争,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘劝赔。我一直安慰自己誓焦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布着帽。 她就那樣靜靜地躺著杂伟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仍翰。 梳的紋絲不亂的頭發(fā)上赫粥,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天,我揣著相機(jī)與錄音予借,去河邊找鬼越平。 笑死频蛔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的秦叛。 我是一名探鬼主播晦溪,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼挣跋!你這毒婦竟也來了三圆?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤浆劲,失蹤者是張志新(化名)和其女友劉穎嫌术,沒想到半個(gè)月后哀澈,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牌借,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年割按,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了膨报。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,918評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡适荣,死狀恐怖现柠,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弛矛,我是刑警寧澤够吩,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站丈氓,受9級特大地震影響周循,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜万俗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一湾笛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闰歪,春花似錦嚎研、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至教翩,卻和暖如春杆勇,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背迂曲。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工靶橱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓关霸,卻偏偏與公主長得像传黄,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子队寇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,926評論 2 361