欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
正確使用Java I/O輸出和讀入數據
前言
Java的I/O系統使用“流”來(lái)處理各種類(lèi)型的輸入、輸出數據的任務(wù)。
在傳輸數據的過(guò)程中,我們需要判斷流中傳輸的數據何時(shí)結束這樣的問(wèn)題。這對于我們正確地發(fā)送和接收數據是非常關(guān)鍵的。
如何判斷流的末尾和批數據的末尾,是解決這個(gè)問(wèn)題的關(guān)鍵。本文就是要深入地分析Java I/O輸入輸出的工作原理,保證我們能夠正確地執行數據的發(fā)送和接收!
Java I/O任務(wù)
一個(gè)Java的I/O任務(wù),創(chuàng )建了一個(gè)連接兩個(gè)系統的數據傳輸管道。它分為兩個(gè)部分:輸入流和輸出流。
輸入流,指的是通過(guò)流向本系統的內存傳輸數據的單向數據傳輸通道。
輸出流,指的是通過(guò)流向外部系統傳輸數據的單向數據傳輸通道。

輸入流

InputStream類(lèi)是表示字節輸入流的所有類(lèi)的超類(lèi)。這是一個(gè)抽象類(lèi)。
我們看它提供的讀入數據的方法:
read
public abstract int read()
                  throws IOException
從輸入流讀取下一個(gè)數據字節。返回 0 到 255 范圍內的 int 字節值。如果因已到達流末尾而沒(méi)有可用的字節,則返回值 -1。在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。
子類(lèi)必須提供此方法的一個(gè)實(shí)現。
返回:
下一個(gè)數據字節,如果到達流的末尾,則返回 -1。
拋出:
IOException - 如果發(fā)生 I/O 錯誤。

--------------------------------------------------------------------------------

read
public int read(byte[] b)
         throws IOException
從輸入流中讀取一定數量的字節并將其存儲在緩沖區數組 b 中。以整數形式返回實(shí)際讀取的字節數。在輸入數據可用、檢測到文件末尾或者拋出異常前,此方法一直阻塞。
如果 b 為 null,將拋出 NullPointerException。如果 b 的長(cháng)度為 0,則無(wú)字節可讀且返回 0;否則,要嘗試讀取至少一個(gè)字節。如果因為流位于文件末尾而沒(méi)有可用的字節,則返回值 -1;否則,至少可以讀取一個(gè)字節并將其存儲在 b 中。
將讀取的第一個(gè)字節存儲在元素 b[0] 中,下一個(gè)存儲在 b[1] 中,依次類(lèi)推。讀取的字節數最多等于 b 的長(cháng)度。讓 k 為實(shí)際讀取的字節數;這些字節將存儲在元素 b[0] 至 b[k-1] 之間,不影響元素 b[k] 至 b[b.length-1]。
如果不是因為流位于文件末尾而無(wú)法讀取讀取第一個(gè)字節,則拋出 IOException。特別是,如果輸入流已關(guān)閉,則拋出 IOException。
類(lèi) InputStream 的 read(b) 方法的效果等同于:
read(b, 0, b.length)
參數:
b - 讀入數據的緩沖區。
返回:
讀入緩沖區的總字節數,如果由于流末尾已到達而不再有數據,則返回 -1。
拋出:
IOException - 如果發(fā)生 I/O 錯誤。
NullPointerException - 如果 b 為 null。
另請參見(jiàn):
read(byte[], int, int)

--------------------------------------------------------------------------------

read
public int read(byte[] b,
                int off,
                int len)
         throws IOException
將輸入流中最多 len 個(gè)數據字節讀入字節數組。嘗試讀取多達 len 字節,但可能讀取較少數量。以整數形式返回實(shí)際讀取的字節數。
在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。
如果 b 為 null,則拋出 NullPointerException。
如果 off 為負,或 len 為負,或 off+len 大于數組 b 的長(cháng)度,則拋出 IndexOutOfBoundsException。
如果 len 為 0,則沒(méi)有字節可讀且返回 0;否則,要嘗試讀取至少一個(gè)字節。如果因為流位于文件末尾而沒(méi)有可用的字節,則返回值 -1;否則,至少可以讀取一個(gè)字節并將其存儲在 b 中。
將讀取的第一個(gè)字節存儲在元素 b[off] 中,下一個(gè)存儲在 b[off+1] 中,依次類(lèi)推。讀取的字節數最多等于 len。讓 k 為實(shí)際讀取的字節數;這些字節將存儲在元素 b[off] 至 b[off+k-1] 之間,其余元素 b[off+k] 至 b[off+len-1] 不受影響。
在任何情況下,元素 b[0] 至 b[off] 和元素 b[off+len] 至 b[b.length-1] 都不會(huì )受到影響。
如果不是因為流位于文件末尾而無(wú)法讀取第一個(gè)字節,則拋出 IOException。特別是,如果輸入流已關(guān)閉,則拋出 IOException。
類(lèi) InputStream 的 read(b, off, len) 方法只重復調用方法 read()。如果第一個(gè)這樣的調用導致 IOException,則從對 read(b, off, len) 方法的調用中返回該異常。如果對 read() 的任何后續調用導致 IOException,則該異常會(huì )被捕獲并將發(fā)生異常時(shí)的位置視為文件的末尾;到達該點(diǎn)時(shí)讀取的字節存儲在 b 中并返回發(fā)生異常之前讀取的字節數。建議讓子類(lèi)提供此方法的更有效的實(shí)現。
參數:
b - 讀入數據的緩沖區。
off - 在其處寫(xiě)入數據的數組 b 的初始偏移量。
len - 要讀取的最大字節數。
返回:
讀入緩沖區的總字節數,如果由于已到達流末尾而不再有數據,則返回 -1。
拋出:
IOException - 如果發(fā)生 I/O 錯誤。
NullPointerException - 如果 b 為 null。
另請參見(jiàn):
read()


read方法解讀
這些方法的核心。實(shí)際上就是read()方法。
這個(gè)方法的JavaDoc中指出:
“如果因已到達流末尾而沒(méi)有可用的字節,則返回值 -1。如果因已到達流末尾而沒(méi)有可用的字節,則返回值 -1。在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。”

1,read方法會(huì )在能夠返回流中的字節之前,一直阻塞線(xiàn)程。這就是說(shuō),read方法是一個(gè)低消耗的監聽(tīng)和讀取I/O傳輸的好方法。
這個(gè)方法的實(shí)現,具有非常高的性能。

2,如果輸入流的I/O系統在執行這個(gè)read方法時(shí)拋出異常,那么顯然這個(gè)方法會(huì )非正常結束,這個(gè)也是毫無(wú)疑問(wèn)的。

3,“如果因已到達流末尾而沒(méi)有可用的字節,則返回值 -1。”
這句話(huà)看似沒(méi)有問(wèn)題,但實(shí)際上有非常大的歧義!什么是流的末尾?只有流的末尾才能返回-1嗎?

InputStream類(lèi)和SocketInputStream類(lèi)的源碼解讀
通過(guò)查看InputStream類(lèi)的源碼,我發(fā)現實(shí)際上,流,就好比是雙向2車(chē)道的高速公路。它傳輸數據是一批一批的。我把它叫做“批數據”。
假設A=======B兩個(gè)系統通過(guò)一個(gè)I/O流來(lái)連接。
那么,從B端通向A端的車(chē)道,就叫作A的“輸入流”。同一條車(chē)道,在B這邊,叫作B的“輸出流”。
同理,從A端通向B端的車(chē)道,就叫作A的“輸出流”。同一條車(chē)道,在B這邊,就叫作B的“輸入流”。

數據在這條高速公路上,不是一條一條跑的,而是一批一批跑。

OutputStream類(lèi),此抽象類(lèi)是表示輸出字節流的所有類(lèi)的超類(lèi)。輸出流接受輸出字節并將這些字節發(fā)送到某個(gè)接收器。

OutputStream類(lèi)的write方法,每執行一次,就向這條高速公路上發(fā)送了一批數據。OutputStream類(lèi)的一些子類(lèi),它們并不是在每次write()方法執行之后立刻把這批數據發(fā)送到數據高速公路上的。而是只有在執行flush()方法之后,才把之前write的多批數據真正地發(fā)送到數據通道中。
這樣,多個(gè)write()方法發(fā)送的數據就變?yōu)榱艘慌鷶祿耍?

通過(guò)read()方法讀入時(shí),當讀完該批數據之后,如果再一次執行read()方法,就會(huì )立刻返回-1。
實(shí)際上,這是并沒(méi)有到達流的末尾!僅僅是讀完了一批發(fā)送的數據而已!

如果我們又一次執行read()方法,那么,如果:
1,流沒(méi)有結束。也就是說(shuō),對面的發(fā)送端可能還會(huì )發(fā)送下一批數據時(shí),就會(huì )進(jìn)入阻塞狀態(tài)。當前線(xiàn)程暫停,直到讀取到輸入流中下一批數據的第一個(gè)字節。
2,流結束了。也就是說(shuō),對面的發(fā)送端不再發(fā)送任何數據,也即:這條數據通道已經(jīng)沒(méi)有用了,這時(shí),可以說(shuō)“到達流的末尾”了!返回-1。
   
所以,InputStream及其子類(lèi)的read()方法的注釋是不完整的!
Read()方法的注釋?zhuān)瑧撨@么說(shuō):
read
public abstract int read()
                  throws IOException
從輸入流讀取下一個(gè)數據字節。返回 0 到 255 范圍內的 int 字節值。
如果在讀完一批數據后首次調用read()方法,那么返回-1。表示這批數據已經(jīng)讀完了!
如果因已到達流末尾而沒(méi)有可用的字節,則返回值 -1。在輸入數據可用、檢測到流的末尾或者拋出異常前,此方法一直阻塞。
子類(lèi)必須提供此方法的一個(gè)實(shí)現。
返回:
下一個(gè)數據字節;
如果剛讀完一批數據,則返回-1;
如果到達流的末尾,則返回 -1。
拋出:
IOException - 如果發(fā)生 I/O 錯誤。


如何正確使用Java I/O輸出和讀入數據
明白了Java的I/O流的工作機理和read方法的執行結果,我們就能夠正確地使用Java I/O系統輸出和讀入數據了。

如何分批輸出數據
由于read(…)方法是分批讀取數據的,所以,我們應該在輸出端正確地分批輸出數據。
Write(…)方法,然后執行flush()方法能夠將多批數據合并成一批數據輸出。
盡管OutputStream這個(gè)基類(lèi)的flush()方法是無(wú)用的,但是由于我們得到的OutputStream類(lèi)型的輸出對象都是這個(gè)類(lèi)的子類(lèi)的對象,所以,我們還是應該盡量使用flush()方法強制向輸出流中物理輸出數據,以避免錯誤。

如何分批讀取數據
    我們常常使用public int read(byte[] b,
                int off,
                int len)
         throws IOException
這個(gè)方法來(lái)讀取一批數據。
查看這個(gè)方法的源代碼,我們可以發(fā)現,它在讀取完一批數據時(shí),又執行了一次read()方法,由于前面論述的原因,這個(gè)方法立刻返回-1,然后這個(gè)方法退出,返回這次讀取的字節數。
因此,如果我們要讀取一批數據,可以采用如下幾種方法:
使用read()判斷-1來(lái)讀完一批數據:
    代碼示例:
Int byte;
While((byte=inputStream.read())!=-1 ){
    Byte就是返回的字節。

}
如果讀完一批數據后再一次執行read方法,將會(huì )立刻返回-1,表示這批數據已經(jīng)讀完。

使用read(byte[] buffer)判斷是否返回小于buffer.length或者-1來(lái)判斷是否讀完一批數據
上面那樣一個(gè)一個(gè)字節讀取數據比較麻煩,我們通常使用一個(gè)字節數組來(lái)讀取數據。
read(byte[] buffer)方法返回:
1,buffer.length,表示從輸入流中讀取到的數據塞滿(mǎn)了這個(gè)字節數組。此時(shí),可能已經(jīng)讀完了這批數據,也可能沒(méi)有讀完這批數據。
    如果剛好讀完,那么再執行一次read()方法,就會(huì )返回-1,表示這批數據已經(jīng)讀完,而不是表示流已經(jīng)結束。
2,小于buffer.length。表示讀完了該批數據。并且執行了一次read()方法,返回-1,表示這批數據已經(jīng)讀完。
3,-1。這批數據已經(jīng)讀完了。 不可能是表示流已經(jīng)結束。因為之前就會(huì )退出while循環(huán)。
   
代碼示例:
Byte[] buffer=new byte[1024];
int size=buffer.length;
While(size!=-1 || size>=buffer.length){
Size=inputStream.read(buffer));
將數據讀到數組buffer中。
如果讀到了-1,或者 讀出的數據少于buffer的尺寸,表示已經(jīng)讀完該批數據,不再循環(huán)讀取數據了!


}


讀入一批數據的操作必須對應輸出一批數據的操作
讀入一批數據的操作必須對應輸出一批數據的操作。否則,讀入數據的線(xiàn)程會(huì )一直阻塞,等待輸出端輸出下一批數據。
如果對方也需要我們提供輸出數據,那么就可能會(huì )使整個(gè)流的兩端的線(xiàn)程互相等待,死鎖住。并且這個(gè)I/O流也會(huì )永遠不釋放,這樣就會(huì )使系統的資源耗盡。

后記:
在前兩天的工作中,我使用Socket在服務(wù)器和客戶(hù)端執行操作時(shí),出現了死鎖的現象。為了找出問(wèn)題的根源,我仔細查看了InputStream類(lèi)和SocketInputStream類(lèi)的源代碼。找出了造成輸入、輸出流誤用的原因。
希望這篇文章能夠幫助飽受I/O輸入、輸出流問(wèn)題困擾的Java程序員!
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
基于java的InputStream.read(byte[] b,int off,int len)算法學(xué)習 .
java中基本輸入輸出流的解釋
java IO(2)字節流和字符流
關(guān)于java中BufferedReader的read()及readLine()方法的使用心得
從TcpSocket上讀取數據的三種方式
徹底轉變流,第 2 部分:優(yōu)化 Java 內部 I/O
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久