Java I/O 系統(tǒng)

所謂 I/O 指的是輸入輸出,輸入輸出的一端是內存(RAM),另一端可以是文件系統(tǒng)中的文件、網(wǎng)絡中的數(shù)據(jù)或者標準輸入輸出設備,如鍵盤、顯示器等。所以 Java 程序在這個數(shù)據(jù)傳輸?shù)倪^程中,相當于一個操作工的角色。

計算機中的數(shù)據(jù)存儲在不同的存儲介質中,有不同的表現(xiàn)形式。在磁盤中是存儲在磁介質的涂層上,光盤中則是利用了光學技術,RAM 隨機存儲器則是以高低電平的方式存儲數(shù)據(jù)。計算機科學中把這些在底層存儲介質上不同表現(xiàn)形式的數(shù)據(jù)統(tǒng)一抽象成二進制表示的 0 和 1 。所以計算機中最小的存儲單位就是位,8 個位組成一個字節(jié),作為數(shù)據(jù)的基本存儲單位。

Java.io 類庫中的類都是按照輸入輸出對應設計的,理解這一點很重要。

文本文件和二進制文件?

文件可以分為文本文件和二進制文件。他們的區(qū)別可以這樣去理解,文本文件是由字符序列構成的,而二進制文件則是由位序列構成的。比如 .java 文件就是文本文件, .class 文件就是二進制文件。

如果研究的更深層次的話,本質上計算機中的任何數(shù)據(jù)都是以二進制的形式存儲的。區(qū)別是當用記事本或者 vim 這樣的編輯器打開文本文件時,它會將二進制數(shù)據(jù)通過其指定的編碼方式,轉換成字符,展示給人看。對于原生的二進制文件,編輯器則沒有此功能。

文本文件讀取到內存中時,需要用其指定的編碼方式,將字符轉換成二進制的形式才能夠存儲到內存中去。而二進制文件因為本來就是原生二進制存儲,所以并不需要轉換,可以直接以字節(jié)的方式讀到內存中去。

文本 I/O 和二進制 I/O

二進制 I/O 是一次讀取一個字節(jié)的方式讀取的數(shù)據(jù),如果用它來讀取二進制文件的話,它就會直接照搬二進制文件中的數(shù)據(jù)到內存中,不需要進行轉換,效率高。舉例:如果要把內存中的數(shù)字 199 寫入到二進制文件中去,由于 199 在內存中本就是以 0xC7 方式存在的,所以直接照搬復制過去就可以了。

文本 I/O 在讀寫字符時會進行一個編碼和解碼的轉換,比如要將字符串 "199"
寫入到文件中去時,會將"1","9","9" 三個字符轉換成 0x31 , 0x39 , 0x39 后,再寫入到文件中去。

二進制 I/O 可以讀取任何類型的數(shù)據(jù),但是文本 I/O 則只能夠讀取由字符序列組成的文本文件。這里的文本 I/O 和 二進制 I/O 就是通常所說的字符流和二進制流。

重點:所有的 I/O 類的構造方法都會通過 throws 聲明不處理 FileNotFoundException 異常,所有的方法幾乎都會聲明不處理 IOException 異常。記住這兩點非常重要!

字節(jié)流

以字節(jié)的方式處理數(shù)據(jù)的流,被分類為字節(jié)流。其中所謂的流可以理解為傳送數(shù)據(jù)的管道,而且還有能力去操縱這些數(shù)據(jù),就是通過流所提供的種種方法。

字節(jié)輸入輸出流的抽象基類

字節(jié)輸入輸出有兩個抽象基類,InputStream 和 OutputStream 。這是兩個抽象類,沒有具體的使用價值,因為它不能創(chuàng)建對象,只能依賴于繼承了它的子類去完成具體功能。為什么要設計出這樣的繼承關系呢?這不就是面向對象的精髓?節(jié)省代碼啊!

學習啟示:學會將之前學習的具體的語法知識點和它的應用聯(lián)系在一起,建立的聯(lián)系越多、越頻繁,才能夠真正達到融匯貫通的層次,多動腦思考。比如這里的抽象類 InputStream 類,它就涉及到關于抽象類無法直接創(chuàng)建對象的具體語法,學會將高一層次的抽象和第一層次的抽象建立聯(lián)系,才能知其然和所以然。

InputStream 類中有幾個重要的方法,下面一一介紹下。

  • int read(byte[] b)實現(xiàn)的功能就是一次讀取一個字節(jié),直到把這個字節(jié)數(shù)組 b 裝滿為止。
  • int read(byte[] b,int off,int len)從流中讀取字節(jié)并將它們保存在下標 off 開始到 len 的位置結束。
  • int read()一次讀取一個字節(jié),但是因為返回值是 int 類型的,占據(jù) 4 個字節(jié),所以會在這一個字節(jié)的基礎上,補充高位的三個字節(jié)作為一個 int 類型的值返回,但這并不影響結果啊。

以上三個方法返回值為實際讀取的字節(jié)數(shù),如果讀到流的末尾,則返回 -1 。

OutputStream 類和 InputStream 類是一一對應的。理解了一個,另外的就理解了。

  • void write(byte[] b)一次性把這個字節(jié)數(shù)組的內容輸出去。
  • void write(byte[] b,int off,int len)從 off 開始的 len 個字節(jié)輸出。
  • void write(int b)參數(shù)是一個 4 個字節(jié)的整數(shù),但是輸出是一個字節(jié),所以會去掉前面三個高位的內容。
  • void flush()強行清空管道中可能遺留的數(shù)據(jù)。

文件流 FileInputStream & FileOutputStream

FileInputStream 和 FileOutputStream 類是專門設計來以字節(jié)的方式操作文件的流,兩者常用的方法就是繼承自它們父類的那幾個方法。

FileInputStream 類構造函數(shù)有FileInputStream(String name)FileInputStream(File file)。

FileOutputStream 類的方法必然是同樣的。有四個構造函數(shù):

  • FileOutputStream(String name)
  • FileOutputStream(File file)
  • FileOutputStream(String name,boolean append)
  • FileOutputStream(File file,boolean append)

前兩個方法都是如果指定的文件存在,則會覆蓋該文件的內容,如果不存在就先創(chuàng)建一個新的文件。后兩個構造方法的第二個參數(shù)如果設置為 true ,如果文件存在會在原來內容的基礎上進行追加,如果不存在當然就是創(chuàng)建一個文件啦。

過濾器數(shù)據(jù)流 FilterInputStream & FilterOutputStream

是為了達到某種目的過濾字節(jié)的流,比如基本的文件流只能讀取字節(jié),但是如果想要直接讀取指定數(shù)據(jù)類型的數(shù)據(jù)該怎么辦呢?這就需要利用過濾器流來完成這個功能了。所以設計了 FilterInputStream 和 FilterOutputStream 來作為過濾流的基類,實際使用中,一般都是用它的子類。這屬于套接流的概念了,在原有字節(jié)流的基礎上套上新的流,大管子套著小管子。

數(shù)據(jù)流 DataOutputStream & DataInputStream

DataOutputStream 和 DataInputStream 類被設計來直接操作 java 語言中的 8 種基本數(shù)據(jù)類型,和以 utf-8 的形式操作字符串,它們繼承自 FilterInputStream / FilterOutputStream 類。

以 DataInputStream 類為例,它有個構造方法DataInputStream(InputStream in)

讀取數(shù)據(jù)有一下這些方法:

  • readBoolean()
  • dis.readByte()
  • dis.readChar()
  • dis.readDouble()
  • readFloat()
  • readInt()
  • readLong()
  • readShort()
  • readUTF()

至于 DataOutputStream 則完全是對應的。

緩沖流 BufferedInputStream & BufferedOutputStream

BufferedInputStream 和 BufferedOutputStream 類的內部有一個數(shù)組protected volatile byte buf[],作為緩沖數(shù)據(jù)區(qū)。所以可以一次讀取多個字節(jié)的數(shù)據(jù)到緩沖區(qū),減少對磁盤的讀寫次數(shù),以此來提高讀寫效率。當對超過 100M 的數(shù)據(jù)時,利用緩沖流讀寫速度能夠得到質的提升。

BufferedInputStream 類有兩個構造函數(shù):

  • BufferedInputStream(InputStream in)
  • BufferedInputStream(InputStream in,int size)此構造函數(shù)的第二個參數(shù)是指定緩沖字節(jié)數(shù)組的大小。

BufferedOutputStream 輸出流是輸入流是對應的。

對象流

ObjectInputStream 和 ObjectOutputStream 類不僅擁有 DataInputStream 和 DataOutputStream 類的直接讀寫基本數(shù)據(jù)類型和字符串的功能,還可以實現(xiàn)對象的輸入、輸出,所以對象流完全可以替代數(shù)據(jù)流。讀寫對象也叫作序列化和反序列化!

ObjectInputStream 類有兩個構造函數(shù):

  • ObjectInputStream()
  • ObjectInputStream(InputStream in)

讀寫對象是通過Object readObject()void writeObject(Object obj)方法實現(xiàn)的,由于創(chuàng)建對象需要事先加載類的字節(jié)碼文件,所以readObject()方法顯示聲明不處理 ClassNotFoundException 異常。

// TODO:

管道流

PipedInputStream 和 PipedOutputStream 是專門設計來在線程之間傳輸數(shù)據(jù)的,可以說是生產者消費者的一個封裝好的解決方案。

在生產者線程和消費者線程之間構建一個唯一傳送數(shù)據(jù)的管道,就能夠極大的簡化線程之間的協(xié)作問題,不需要再去用 sychronized 同步鎖、notify() 和 wait() 方法的組合弄一個復雜的邏輯去完成協(xié)作功能了。那如何構建呢?生產者的輸出管道套著消費者的輸入管道,兩個管道構成一個管道,就能夠解決問題了。

PipedInputStream 類有一個構造方法PipedInputStream(PipedOutputStream src),PipedOutputStream 類有一個構造方法PipedOutputStream(PipedInputStream snk)。兩個輸入輸出流的組合就可以了。組合方式如下:

PipedInputStream pis = new PipedInputStream();
PipedOutputStream pos = new PipedOutputStream(pis);
//或者
PipedOutputStream pos = new PipedOutputStream();
PipedInputStream pis = new PipedInputStream(pos);

隨機流

這里涉及到一個隨機流和順序流的概念,所謂順序流就是類似磁帶那種只能從前往后順序讀寫的流,只能夠順序訪問或讀寫文件。除了這里即將了解到的 RandomAccessFile 類,其他都屬于順序流。所謂隨機流就是可以在文件的任意位置上進行讀寫,所以隨機流擁有更新文件的能力。

RandomAccessFile 方法直接繼承自 Object 類,同時擁有對于 8 種基本數(shù)據(jù)類型的讀和寫操作。而且不分輸入和輸出流,直接通過構造函數(shù)的參數(shù)指定。

RandomAccessFile 類的兩個構造函數(shù)如下:

  • RandomAccessFile(File file,String mode)
  • RandomAccessFile(String name,String mode)

隨機流是通過參數(shù) "r""rw"來指定流的讀寫方式的,第一個表示只讀,第二個表示可以讀和寫。

RandomAccessFile 類之所以能夠直接對文件中的任意位置進行讀寫操作,就是因為有void seek(long pos)方法作支撐。 RandomAccessFile 類管理的隨機流中有一個文件指針作為定位器,來定位文件中的字節(jié)位置。參數(shù) pos 為 0 表示此時指針指向第 0 個字節(jié)的起始位置,每次讀取指定數(shù)量字節(jié)后,會自動偏移指定數(shù)量字節(jié)到新的位置。

標準流

就是 System 類的那三個

字符流

InputStreamReader 和 OutputStreamWriter 是字符流的基類。

BufferedReader 有一個 readLine() 方法。

學習啟示:上課不認真聽講,課后又沒有及時復盤整理,導致筆記無法動筆。這說明上課要認真聽講,筆記要及時整理才行。如果真的上課老師講的不清楚或者自己沒聽懂,課后自己找資料去學習后,再來整理筆記也是可以的。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容