按照流的方向:
輸入流(InputStream);
輸出流(OutputStream)。
按照實現(xiàn)功能,是否直接與特定的地方(如磁盤、內(nèi)存、設(shè)備等)相連:
節(jié)點流:可以從或向一個特定的地方(節(jié)點)讀寫數(shù)據(jù),如FileReader;
處理流:是對一個已存在的流的連接和封裝,通過所封裝的流的功能調(diào)用實現(xiàn)數(shù)據(jù)讀寫。如BufferedReader。處理流的構(gòu)造方法總是要帶一個其他的流對象做參數(shù)。一個流對象經(jīng)過其他流的多次包裝,稱為流的鏈接。
按照處理數(shù)據(jù)的單位:
字節(jié)流:字節(jié)流繼承于InputStream和OutputStream;
字符流:字符流繼承于Reader和Writer。
兩種方式:
實現(xiàn)Cloneable接口并重寫Object 類中的clone()方法;
實現(xiàn)Serializable接口,通過對象的序列化和反序列化實現(xiàn)克隆,可以實現(xiàn)真正的深度克隆。
緩沖區(qū)就是一段特殊的內(nèi)存區(qū)域,很多情況下當程序需要頻繁地操作一個資源(如文件或數(shù)據(jù)庫)則性能會很低,所以為了提升性能就可以將一部分數(shù)據(jù)暫時讀寫到緩存區(qū),以后直接從此區(qū)域中讀寫數(shù)據(jù)即可,這樣就可以顯著的提升性能。
對于Java字符流的操作都是在緩沖區(qū)操作的,所以如果我們想在字符流操作中主動將緩沖區(qū)刷新到文件則需要使用flush()方法實現(xiàn)。
在IO包中主要由4個可用的Filter流,分別為:
FilterInputStream:是InputStream直接子類,包含其他一些字節(jié)輸入流,它將這些流用作其基本數(shù)據(jù)源,本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的InputStream的所有方法。
FilterOutputStream:是OutputStream直接子類,包含其他一些字節(jié)輸出流,它將這些流用作其基本數(shù)據(jù)源,類本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的OutputStream的所有方法。
FilterReader:是Reader直接子類,包含其他一些字符輸入流,它將這些流用作其基本數(shù)據(jù)源,本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的Readder的所有方法。
FilterWriter:是Writer直接子類,包含其他一些字符輸出流,它將這些流用作其基本數(shù)據(jù)源,本身只是簡單地重寫那些將所有請求傳遞給所包含輸入流的Writer的所有方法。
Filter流都是抽象類,不能被實例化的。
流是一種抽象概念,它代表了數(shù)據(jù)的無結(jié)構(gòu)化傳遞。
用來進行輸入輸出操作的流就稱為IO流,換句話說,IO流就是以流的方式進行輸入輸出。
從文件中讀取數(shù)據(jù)存儲到程序的進程中叫做輸入流。
從程序的進程中讀取數(shù)據(jù)然后寫入到目標文件中叫做輸出流。
字節(jié)流的操作不經(jīng)過緩沖區(qū)(內(nèi)存),直接操作文件本身;
字符流的操作會先經(jīng)過緩沖區(qū)(內(nèi)存)然后通過緩沖區(qū)再操作文件;
字節(jié)流按照8位傳輸,以字節(jié)為單位輸入輸出數(shù)據(jù);
字符流按照16位傳輸,以字符為單位輸入輸出數(shù)據(jù)。
序列化就是一種用來處理對象流的機制,將對象的內(nèi)容進行流化,對流化后的對象進行讀寫操作。
序列化的實現(xiàn):
將需要被序列化的類實現(xiàn)Serializable接口,沒有需要實現(xiàn)的方法,此接口只是為了標注對象可被序列化的;
然后使用一個輸出流(如:FileOutputStream)來構(gòu)造一個ObjectOutputStream對象,再使用該對象的write(Object obj)方法,將參數(shù)obj的對象輸出。
IO操作包括:對硬盤的讀寫、對socket(網(wǎng)絡(luò))的讀寫以及外設(shè)的讀寫。
阻塞IO:當用戶線程發(fā)起一個IO讀請求操作,首先查看要讀取的數(shù)據(jù)是否就緒,如果數(shù)據(jù)沒有就緒,則會一直在那等待,直到數(shù)據(jù)就緒;
非阻塞IO:當用戶線程發(fā)起一個IO讀請求操作,首先查看要讀取的數(shù)據(jù)是否就緒,如果數(shù)據(jù)沒有就緒,則會返回一個標志信息告知用戶線程當前要讀的數(shù)據(jù)沒有就緒。當數(shù)據(jù)就緒之后,便將數(shù)據(jù)拷貝到用戶線程,這樣才完成了一個完整的IO讀請求操作,也就是說一個完整的IO讀請求操作包括兩個階段:
查看數(shù)據(jù)是否就緒;
進行數(shù)據(jù)拷貝(內(nèi)核將數(shù)據(jù)拷貝到用戶線程)。
Java中傳統(tǒng)的IO都是阻塞IO,比如通過socket來讀數(shù)據(jù),調(diào)用read()方法之后,如果數(shù)據(jù)沒有就緒,當前線程就會一直阻塞在read方法調(diào)用那里,直到有數(shù)據(jù)才返回;而如果是非阻塞IO的話,當數(shù)據(jù)沒有就緒,read()方法應(yīng)該返回一個標志信息,告知當前線程數(shù)據(jù)沒有就緒,而不是一直在那里等待。
輸入流就是從外部文件輸入到內(nèi)存,輸出流主要是從內(nèi)存輸出到文件。
IO 流主要分為字符流和字節(jié)流。
字節(jié)流中有抽象類InputStream和OutputStream,常見子類有FileInputStream、FileOutputStream、BufferedOutputStream等。
字符流中有抽象類Reader和Writer,常見的子類有FilterReader、FilterWriter等。
常見的接口:
Closeable:關(guān)閉資源
Flushable:刷新緩沖區(qū)
Appendable:追加
Java中的阻塞式方法是指在程序調(diào)用該方法時,必須等待輸入數(shù)據(jù)可用或者檢測到輸入結(jié)束或者拋出異常,否則程序會一直停留在該語句上,不會執(zhí)行下面的語句,比如read()和readLine()方法。
Java NIO是非阻塞式IO,由以下幾個核心部分組成:
Channels
Buffers
Selectors
Channel有點象流,數(shù)據(jù)可以從Channel讀到Buffer中,也可以從Buffer寫到Channel中。Channel和Buffer有好幾種類型,下面是JAVA NIO中的一些主要Channel的實現(xiàn):
FileChannel(文件)
DatagramChannel(UDP)
SocketChannel(TCP)
ServerSocketChannel(網(wǎng)絡(luò))
以下是Java NIO里關(guān)鍵的Buffer實現(xiàn):
ByteBuffer
CharBuffer
DoubleBuffer
FloatBuffer
IntBuffer
LongBuffer
ShortBuffer
Selector:允許單線程處理多個Channel。如果你的應(yīng)用打開了多個連接(通道),但每個連接的流量都很低,使用Selector就會很方便,一個單線程中使用一個Selector處理3個Channel的圖示:
傳統(tǒng)IO一般是一個線程等待連接,連接過來之后分配給processor線程,processor線程與通道連接后如果通道沒有數(shù)據(jù)過來就會阻塞(線程被動掛起)不能做別的事情。
NIO則不同,首先,在selector線程輪詢的過程中就已經(jīng)過濾掉了不感興趣的事件,其次,在processor處理事件的read和write都是非阻塞操作即直接返回的,線程沒有被掛起。
傳統(tǒng)的IO中,每個連接創(chuàng)建一個線程,NIO可以用一個含有限數(shù)量線程的線程池,甚至一個線程為多個連接服務(wù)。
傳統(tǒng)IO的通道是單向的,NIO的通道是雙向的。
BIO:同步并阻塞,服務(wù)器的實現(xiàn)模式是一個連接一個線程,這樣的模式很明顯的一個缺陷是:由于客戶端連接數(shù)與服務(wù)器線程數(shù)成正比關(guān)系,可能造成不必要的線程開銷,嚴重的還將導(dǎo)致服務(wù)器內(nèi)存溢出。當然,這種情況可以通過線程池機制改善,但并不能從本質(zhì)上消除這個弊端。
NIO:在JDK1.4以前,Java的IO模型一直是BIO,但從JDK1.4開始,JDK引入的新的IO模型NIO,它是同步非阻塞的。而服務(wù)器的實現(xiàn)模式是多個請求一個線程,即請求會注冊到多路復(fù)用器Selector上,多路復(fù)用器輪詢到連接有IO請求時才啟動一個線程處理。
AIO:JDK1.7發(fā)布了NIO2.0,這就是真正意義上的異步非阻塞,服務(wù)器的實現(xiàn)模式為多個有效請求一個線程,客戶端的IO請求都是由OS先完成再通知服務(wù)器應(yīng)用去啟動線程處理(回調(diào))。
應(yīng)用場景:并發(fā)連接數(shù)不多時采用BIO,因為它編程和調(diào)試都非常簡單,但如果涉及到高并發(fā)的情況,應(yīng)選擇NIO或AIO,更好的建議是采用成熟的網(wǎng)絡(luò)通信框架Netty。
注(不用回答,問道再答):
同步:Java自己去處理IO。
異步:Java將IO交給操作系統(tǒng)去處理,告訴緩存區(qū)大小,處理完成回調(diào)。
阻塞:使用阻塞IO時,Java調(diào)用會一直阻塞到讀寫完成才返回。
非阻塞:使用非阻塞IO時,如果不能立馬讀寫,Java調(diào)用會馬上返回,當IO事件分發(fā)器通知可讀寫時在進行讀寫,不斷循環(huán)直到讀寫完成。
PrintStream:
PrintStream是字節(jié)流,并且是打印流;
PrintStream不會拋出IOException,可以通過checkError()來判斷是否發(fā)生異常;
PrintStream構(gòu)造的參數(shù)可以是File、String、OutputStream;
PrintStream構(gòu)造的參數(shù)可以設(shè)置字符集;
PrintStream構(gòu)造方法可指定參數(shù),實現(xiàn)自動刷新緩存autoflush;
PrintStream寫入速度較慢;
PrintStream提供了print、println方法實現(xiàn)打印。
PrintWriter:
PrintWriter是字符流,并且是打印流;
PrintWriter不會拋出IOException,可以通過checkError()來判斷是否發(fā)生異常;
PrintStream構(gòu)造的參數(shù)可以是File、OutputStream、String、Writer;
PrintWriter 構(gòu)造方法可指定參數(shù),實現(xiàn)自動刷新緩存autoflush;
PrintWriter帶有緩沖區(qū),多次寫入數(shù)據(jù)速度有一定優(yōu)勢;
PrintStream提供了print、println方法實現(xiàn)打印。
BufferedWriter:
BufferedWriter是字符流;
BufferedWriter構(gòu)造的參數(shù)只能是Writer;
BufferedWriter帶有緩沖區(qū),并且可以設(shè)置緩沖區(qū)大小,多次寫入數(shù)據(jù)速度有一定優(yōu)勢。
BufferedWriter提供了newLine方法創(chuàng)建新行。