一、I/O
1. I/O操作中的設計模式
概要
- 以設計模式角度,自頂向下理解I/O原始碼結構
- 理解位元組與字元的關係
1.1 裝飾者模式(輸入流為例)
- 背景:通過繼承擴充套件物件耦合度高,使用裝飾者擴充套件可以在不改變現有結構的情況下,動態地給物件增加額外功能,耦合度底且靈活,一個具體物件可以有多個裝飾者
- 位元組流
抽象構件
:第二行,InputStream介面,定義位元組流的基本操作抽象裝飾者
:第三行,與抽象構建介面
是組合關係,動態的傳入具體構件。第四行通過擴充套件抽象構件子類,為具體構件新增新的功能具體構件
:第一行,實現抽象構件
操作,具體裝飾者
為每一個具體的構件新增新的職責具體裝飾者
:第四行,有新職責的具體構建
- 裝飾者模式為位元組流帶來的增強
-
- 使用
InputStream
時,是以一個位元組一個位元組形式讀或寫,而BufferedInputStream
與BufferedOutputStream
為位元組流提供了緩衝區,讀資料時一次性讀取一塊資料放到緩衝區中,當快取區讀取完後,輸入流會再次填充緩衝區,直到輸入流被讀取完,緩衝區可以減少IO操作。
- 使用
-
DataInputStream
,從位元組流中靈活的讀取並重建Java的基本型別與String型別資料
1.2 介面卡模式(輸入流為例)
- 背景:需要開發的業務功能在元件庫中已經存在,但與新的介面規範不相容,重新開發成本太高,所以使用介面卡模式能解決這些問題
- 已有字元流讀寫介面
Reader
與Writer
,新的需求是位元組流訪問資料來源,然後由字元流處理
- 為什麼使用自符流
-
- 根本原因:記憶體中資料操作是以位元組為單位(給機器看的);一般持久化到磁碟不同的編碼對應不同的字元(給人類看的),也可以以位元組形式持久化到硬碟,供軟體與硬體閱讀。
-
- 位元組流操作單元為位元組(8byte)。InputStream中的read()方法,是以
一個位元組為單位讀取,讀到末尾返回-1
、它的過載方法read(byte[])內部是通過for迴圈呼叫read()
實現一次讀入一個位元組陣列
,按位元組的read()方法的會有頻繁IO操作,普通IO模型也會阻塞執行緒,直到返回一個位元組資料或-1,效率太低
- 位元組流操作單元為位元組(8byte)。InputStream中的read()方法,是以
-
- 字元流操作單元為Unicode碼點(16byte),使用快取讀寫。將資料持久化到磁碟 ,使用位元組寫入會亂碼,因為不同語言(漢語、英語等)都有自己對應的編碼表,例如英文一個字母可以用一個位元組表示,但漢語需要用兩個位元組,甚至一些特殊符號需要更多位元組(Unicode的輔助字元),一個位元組一個位元組寫入很大可能會亂碼。所以字元符流會先根據對應的碼錶將內容寫入緩衝區,緩衝區滿了持久化到磁碟。使用字元流有兩個好處
-
- 利用快取讀寫,避免記憶體與作業系統頻繁IO操作,提高效率
-
- 寫入時指定編碼表可以有效避免亂碼問題
-
介面卡模式中字元流與位元組流
-
字元流
-
Reader
-
Writer
-PS
:個人筆記,望讀者勘誤。本文只例舉了位元組輸入流與字元輸入流兩種,若讀者理解了可以結合原始碼看輸出流中設計模式