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