初识 JAVA IO
2019獨角獸企業重金招聘Python工程師標準>>>
由于本人畫圖太渣,本文圖片均copy自互聯網
什么是I/O
通常定義:
I/O輸入/輸出(Input/Output),分為IO設備和IO接口兩個部分。 在POSIX兼容的系統上,例如Linux系統,I/O操作可以有多種方式,比如DIO(Direct I/O),AIO(Asynchronous I/O,異步I/O),Memory-Mapped I/O(內存映射I/O)等,不同的I/O方式有不同的實現方式和性能,在不同的應用中可以按情況選擇不同的I/O方式。
IO編程廖雪峰的博客:
在計算機中指Input/Output,也就是輸入和輸出。由于程序和運行時數據是在內存中駐留,由CPU這個超快的計算核心來執行,涉及到數據交換的地方,通常是磁盤、網絡等,就需要IO接口。比如你打開瀏覽器,訪問新浪首頁,瀏覽器這個程序就需要通過網絡IO獲取新浪的網頁。瀏覽器首先會發送數據給新浪服務器,告訴它我想要首頁的HTML,這個動作是往外發數據,叫Output,隨后新浪服務器把網頁發過來,這個動作是從外面接收數據,叫Input。所以,通常,程序完成IO操作會有Input和Output兩個數據流。當然也有只用一個的情況,比如,從磁盤讀取文件到內存,就只有Input操作,反過來,把數據寫到磁盤文件里,就只是一個Output操作。 IO編程中,Stream(流)是一個很重要的概念,可以把流想象成一個水管,數據就是水管里的水,但是只能單向流動。Input Stream就是數據從外面(磁盤、網絡)流進內存,Output Stream就是數據從內存流到外面去。對于瀏覽網頁來說,瀏覽器和新浪服務器之間至少需要建立兩根水管,才可以既能發數據,又能收數據。 由于CPU和內存的速度遠遠高于外設的速度,所以,在IO編程中,就存在速度嚴重不匹配的問題。舉個例子來說,比如要把100M的數據寫入磁盤,CPU輸出100M的數據只需要0.01秒,可是磁盤要接收這100M數據可能需要10秒,怎么辦呢?有兩種辦法: 第一種是CPU等著,也就是程序暫停執行后續代碼,等100M的數據在10秒后寫入磁盤,再接著往下執行,這種模式稱為同步IO; 另一種方法是CPU不等待,只是告訴磁盤,“您老慢慢寫,不著急,我接著干別的事去了”,于是,后續代碼可以立刻接著執行,這種模式稱為異步IO。 同步和異步的區別就在于是否等待IO執行的結果。好比你去麥當勞點餐,你說“來個漢堡”,服務員告訴你,對不起,漢堡要現做,需要等5分鐘,于是你站在收銀臺前面等了5分鐘,拿到漢堡再去逛商場,這是同步IO。 你說“來個漢堡”,服務員告訴你,漢堡需要等5分鐘,你可以先去逛商場,等做好了,我們再通知你,這樣你可以立刻去干別的事情(逛商場),這是異步IO。 很明顯,使用異步IO來編寫程序性能會遠遠高于同步IO,但是異步IO的缺點是編程模型復雜。想想看,你得知道什么時候通知你“漢堡做好了”,而通知你的方法也各不相同。如果是服務員跑過來找到你,這是回調模式,如果服務員發短信通知你,你就得不停地檢查手機,這是輪詢模式。總之,異步IO的復雜度遠遠高于同步IO。 操作IO的能力都是由操作系統提供的,每一種編程語言都會把操作系統提供的低級C接口封裝起來方便使用。
java io 體系如下圖:
流
定義:
代表任何有能力產出數據的數據源對象(能read)或者是有能力接收數據的接收端對象(能write)。 在java中,已經將流抽象成輸入輸出對象,就像水管一樣,將兩個容易連接起來。 流是一組有順序的,有起點和終點的字符集合,是對數據傳輸的總稱或抽象。本質:
數據傳輸,根據數據傳輸特性將流抽象為各種類,方便更直觀的進行數據操作。作用:
為數據源和目的地建立一個輸送通道。特性:
相對于程序來說,輸出流是往存儲介質或數據通道寫入數據,而輸入流是從存儲介質或數據通道中讀取數據,一般來說關于流的特性有下面幾點:1. 先進先出,最先寫入輸出流的數據最先被輸入流讀取到。2. 順序存取,可以一個接一個地往流中寫入一串字節,讀出時也將按寫入順序讀取一串字節,不能隨機訪問中間的數據。(RandomAccessFile可以從文件的任意位置進行存取(輸入輸出)操作)3. 只讀或只寫,每個流只能是輸入流或輸出流的一種,不能同時具備兩個功能,輸入流只能進行讀操作,對輸出流只能進行寫操作。在一個數據傳輸通道中,如果既要寫入數據,又要讀取數據,則要分別提供兩個流。java流
進入正題之前,我們先看張圖,以便有更深的了解。
Java的IO模型設計非常優秀,它使用Decorator(裝飾者)模式,按功能劃分Stream,您可以動態裝配這些Stream,以便獲得您需要的功能。
分類
字符流的由來: Java中字符是采用Unicode標準,一個字符是16位,即一個字符使用兩個字節來表示。為此,JAVA中引入了處理字符的流。因為數據編碼的不同,而有了對字符進行高效操作的流對象。本質其實就是基于字節流讀取時,去查了指定的碼表。
幾大抽象類
InputStream
IO 中輸入字節流的繼承圖可見上圖,可以看出:
InputStream是所有的輸入字節流的父類,它是一個抽象類。 ByteArrayInputStream、StringBufferInputStream(上圖的StreamBufferInputStream)、FileInputStream是三種基本的介質流,它們分別從Byte數組、StringBuffer、和本地文件中讀取數據。 PipedInputStream是從與其它線程共用的管道中讀取數據. ObjectInputStream和所有FilterInputStream的子類都是裝飾流(裝飾器模式的主角)。InputStream中的三個基本的讀方法
abstract int read() :讀取一個字節數據,并返回讀到的數據,如果返回-1,表示讀到了輸入流的末尾。intread(byte[]?b) :將數據讀入一個字節數組,同時返回實際讀取的字節數。如果返回-1,表示讀到了輸入流的末尾。intread(byte[]?b, int?off, int?len) :將數據讀入一個字節數組,同時返回實際讀取的字節數。如果返回-1,表示讀到了輸入流的末尾。off指定在數組b中存放數據的起始偏移位置;len指定讀取的最大字節數。其它方法
long skip(long?n):在輸入流中跳過n個字節,并返回實際跳過的字節數。int available() :返回在不發生阻塞的情況下,可讀取的字節數。void close() :關閉輸入流,釋放和這個流相關的系統資源。voidmark(int?readlimit) :在輸入流的當前位置放置一個標記,如果讀取的字節數多于readlimit設置的值,則流忽略這個標記。void reset() :返回到上一個標記。booleanmarkSupported() :測試當前流是否支持mark和reset方法。如果支持,返回true,否則返回false。流結束的判斷:方法read()的返回值為-1時;readLine()的返回值為null時。
OutputStream
IO 中輸出字節流的繼承圖可見上圖,可以看出:
OutputStream是所有的輸出字節流的父類,它是一個抽象類。 ByteArrayOutputStream、FileOutputStream是兩種基本的介質流,它們分別向Byte數組、和本地文件中寫入數據。 PipedOutputStream是向與其它線程共用的管道中寫入數據。 ObjectOutputStream和所有FilterOutputStream的子類都是裝飾流。outputStream中的三個基本的寫方法
abstract void write(int?b):往輸出流中寫入一個字節。 void write(byte[]?b) :往輸出流中寫入數組b中的所有字節。 void write(byte[]?b, int?off, int?len) :往輸出流中寫入數組b中從偏移量off開始的len個字節的數據。其它方法
void flush() :刷新輸出流,強制緩沖區中的輸出字節被寫出。 void close() :關閉輸出流,釋放和這個流相關的系統資源。Reader
在上面的繼承關系圖中可以看出:
Reader是所有的輸入字符流的父類,它是一個抽象類。 CharReader、StringReader是兩種基本的介質流,它們分別將Char數組、String中讀取數據。 PipedReader是從與其它線程共用的管道中讀取數據。 BufferedReader很明顯就是一個裝飾器,它和其子類負責裝飾其它Reader對象。 FilterReader是所有自定義具體裝飾流的父類,其子類PushbackReader對Reader對象進行裝飾,會增加一個行號。 InputStreamReader是一個連接字節流和字符流的橋梁,它將字節流轉變為字符流。FileReader可以說是一個達到此功能、常用的工具類,在其源代碼中明顯使用了將FileInputStream轉變為Reader的方法。我們可以從這個類中得到一定的技巧。Reader中各個類的用途和使用方法基本和InputStream中的類使用一致。后面會有Reader與InputStream的對應關系。主要方法:
(1) public int read() throws IOException; //讀取一個字符,返回值為讀取的字符 (2) public int read(char cbuf[]) throws IOException; /*讀取一系列字符到數組cbuf[]中,返回值為實際讀取的字符的數量*/ (3) public abstract int read(char cbuf[],int off,int len) throws IOException; /*讀取len個字符,從數組cbuf[]的下標off處開始存放,返回值為實際讀取的字符數量,該方法必須由子類實現*/Writer
在上面的關系圖中可以看出:
Writer是所有的輸出字符流的父類,它是一個抽象類。 CharArrayWriter、StringWriter是兩種基本的介質流,它們分別向Char數組、String中寫入數據。PipedWriter是向與其它線程共用的管道中寫入數據, BufferedWriter是一個裝飾器為Writer提供緩沖功能。 PrintWriter和PrintStream極其類似,功能和使用也非常相似。 OutputStreamWriter是OutputStream到Writer轉換的橋梁,它的子類FileWriter其實就是一個實現此功能的具體類(具體可以研究一SourceCode)。功能和使用和OutputStream極其類似.主要方法:
public void write(int c) throws IOException; //將整型值c的低16位寫入輸出流 public void write(char cbuf[]) throws IOException; //將字符數組cbuf[]寫入輸出流 public abstract void write(char cbuf[],int off,int len) throws IOException; //將字符數組cbuf[]中的從索引為off的位置處開始的len個字符寫入輸出流 public void write(String str) throws IOException; //將字符串str中的字符寫入輸出流 public void write(String str,int off,int len) throws IOException; //將字符串str 中從索引off開始處的len個字符寫入輸出流字符流和字節流的轉換
轉換流:
在IO中還存在一類是轉換流,將字節流轉換為字符流,同時可以將字符流轉化為字節流。
InputStreamReader:字節到字符的橋梁OutputStreamWriter:字符到字節的橋梁OutputStreamWriter:將字節流以字符流輸出。InputStreamReader:將字節流以字符流輸入。轉載于:https://my.oschina.net/lwl1989/blog/2209280
總結
以上是生活随笔為你收集整理的初识 JAVA IO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NUXT内存泄漏引发问题
- 下一篇: spring-boot-admin 2.