麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Java > 正文

Java 網絡編程---I/O部分學習筆記整理1

2019-11-17 06:34:30
字體:
來源:轉載
供稿:網友

       網絡程序的很大一部分是簡單的輸入輸出,即從一個系統向另一個系統移動字節。字節就是字節,在很大程度上,讀服務器發送的數據與讀取文件沒什么不同;向客戶傳送數據與寫入一個文件也沒有什么區別。

       java中輸入和輸出組織不同于大多數其他語言。它是建立在流(stream)上。不同的基本流類(如java.io.FileInputStream和sun.net.TelnetOutputStream)用于讀寫特定的數據資源。但是所有的基本輸出流使用同一種基本方法讀數據。

       過濾器流可以連接到輸入流或輸出流。它可以修改已經讀出或寫人的數據(例如,加密或壓縮數據),或者可以簡單地提供附加方法將已經讀出或寫入的數據轉化成其他格式。

       最后Reader和Writer也可以鏈接到輸入流和輸出流,從而答應程序讀出和寫入文本(即字符)而不是字節。假如使用正確,Reader和Writer能夠處理多種類型的字符編碼,包括SJIS和UTF-8等多字節字符集。

 

一、輸出流

java的基本輸出流是 java.io.OutputStream.

public abstract class OutputStream

n         public abstract void write(int b) throws IOException

n         public void write(byte[] data) throws IOException

n         public void write(byte[] data,int offset,int length) throws IOException

n         public void flush() throws IOException

n         public void close() throws IOException

OutputStream的子類使用這些方法向指定媒體寫入數據。

 

我使用相信,我們理解了問什么它們存在,就會更好地記住它們,好,現在開始說一下OutputStream類的方法的由來

Ø         public abstract void write(int b) throws IOException

OutputStream的基本方法是write(int b)。該方法將介于0到255之間的整數看作變量,并將相應的字節寫到一個輸出流。該方法聲明是個抽象方法,因為子類需要改變它以處理特定媒體。例如,ByteArrayOutputStream可以使用拷貝字節到其數組的純Java代碼來實現方法。但是,FileOutputStream就需要使用代碼,此代碼應該理解如何在主機平臺上將數據寫入文件。注重:盡管該方法把整形值作為變量,但是它實際上寫入的是一個無符號字節。Java沒有無符號字節數據類型,因此這里使用整型來代替。無符號字節和有符號字節之間的真正區別是編譯器對它們的解釋。二者都是由8位組成,并且當使用write(int b)將一個int寫入到網絡連接流時,只有8位數據傳送。假如將一個超出0-255范圍的int傳給write(int b),則寫入該數字的低位字節,而忽略余下的三個字節(大家都知道java的int是4個字節的,這里本質就是將int轉換為byte)。

 

Ø         public void write(byte[] data) throws IOException和public void write(byte[] data,int offset,int length) throws IOException

每次寫入一個字節通常效率不高。因此,大部分TCP/ip程序將數據存入一定長度的緩沖區,即在內存中累積字節,并僅當累積了一定數目字節或過了一定的時間段,才將它們發送到最終的目的地。因此write(byte[] data)和write(byte[] data,int offset,int length)就是這樣產生了。

 

Ø         public void flush() throws IOException

我們可以在軟件中或直接在Java代碼中對流實施緩沖操作,也可以在網絡硬件中對流實施緩沖操作。就似乎BufferedOutputStream或BufferedWriter鏈接到底層流來實現流緩沖。因此,假如正在寫入數據,則刷新輸出流是相當重要的。例如,假設已經寫入了一個300字節的請求給一個HTTP Keep-Alive的HTTP服務器,通常希望在發送更多數據之間等待響應。但是,假如輸出流有一個1024字節的緩沖區,則該流可能在將數據發送出緩沖區之前正在等待更多的數據到達,但是這些數據似乎不會到達的,因為它們還沒有發送出去,但是緩沖流不會發送數據給服務器,除非它從底層流獲得更多的數據,但是底層流不會發送更多的數據,除非它從服務器獲得數據,而服務器不會發送數據,除非它獲得保留在緩沖區中的數據(死鎖了!),flush()方法就可以解決了這個僵局,因為即使緩沖區未滿,他也會強制要求實行緩沖操作的流傳送數據。注重:是否對流實行了緩沖操作,這決定于你如何獲得指向流的引用(例如,不論是否希望對System.out執行緩沖操作,都會對其實施緩沖)。假如刷新流需要刷新時,就必須刷新,但是假如刷新失敗了就會導致不可預料、不可重復的程序掛起(flush()返回值是void啊),假如事先不了解掛起問題所在,就很難解決這個問題了。因此,在關閉所有流之前,應當立即刷新它們。否則,關閉流前,緩沖區中的剩余數據可能會丟失。

 

Ø         public void close() throws IOException

最后當利用完流之后,應當調用close()方法關閉流。它會釋放所有與這個流相關的資源,如文件句柄或端口。一旦輸出流關閉了,再向其寫入數據就會觸發IOException異常。但是,有些類型可能答應對對象進行一定操作。如一個已關閉的ByteArrayOutputStream仍然可以轉化成一個實際的字節數組,而且一個已關閉的DigestOutputStream仍可以返回其摘要。

 

二、輸入流

java的基本輸入流是java.io.InputStream

public abstract class InputStream

n         public abstract int read() throws IOException

n         public int read(byte[] data) throws IOException

n         public int read(byte[] data,int offset,int length) throws IOException

n         public long skip(long n) throws IOException

n         public int available() throws IOException

n         public void close() throws IOException

InputStream的具體子類使用這些方法從指定媒體讀取數據。但是不論讀取何種資源,幾乎只能使用這六種方法。有時你甚至可能不知道正在從哪種類型的流中讀取數據。如隱藏在sun.net包中TelnetInputStream是一個文檔沒有說明的類。TelnetInputStream的實例由java.net包中的多種方法返回;如java.net.URL的openStram()方法。但是,這些方法僅聲明了返回InputStream,而不是更加明確的子類TelnetInputStream,這又是多態性在起作用了。子類的實例可以作為超類的實例透明使用。

來了,又來說明方法的由來了。

Ø         public abstract void read() throws IOException

InputStream類的基本方法是沒有參量的read()方法(這個與OutputStream不同了)。該方法從輸入流資源讀取一個單個字節數據并將數據作為0到255之間的數返回,返回-1時表示流的結尾。因為Java沒有無符號字節的數據類型,所以數據以整型類型返回。Read()方法等待和阻塞該方法后人和代碼的執行,直到獲得數據的一個字節并預備讀取該字節。因此,輸入和輸出可能相當慢,這時用戶假如需要完成其他比較重要的任務時,最好試圖將I/O放到它們自己的線程中。Read()方法被聲明為抽象方法,因為子類需要改變它來處理特定媒體。給個例子

byte[] input=new byte[10];

for(int i=0;i<input.length;i++){

       int b=in.read();

       if(b==-1) break;

       input[i]=(byte)b;

}

上面盡管read()方法僅讀取字節,但是它返回的是整型值。因此在將結果存儲到字節數組之前,需要一個類型轉換的過程。當然,這會產生一個介于-128到127的有符號字節,而不是read()方法返回的0到255之間的一個無符號字節。但是,只要用戶清楚使用的是無符號還是有符號字節就不會有很大問題。因此,我們可以把一個有符號字節轉化成無符號字節(轉換的原因是只有范圍在0-255的整數才可以被存儲在java的一個byte類型的變量中)。

int i=b>=0?b:256+b;

這里費了大篇幅,說明了read()返回的與java的byte類型的處理問題,大家可要注重阿,假如對java的原始數據類型還有愛好,可以看一下我的原始數據類型學習筆記(未完成)。

 

Ø         public int read(byte[] data) throws IOException、public int read(byte[] data,int offset,int length) throws IOException

每次讀取一個字節和每次寫入一個字節效率都不高,因此read(byte[] data)和read(byte[] data,int offset,int length)也相應產生了。這兩個方法將從流中讀取的多個字節填充到一個指定的數組中。注重:這些填充到數組的操作不一定會成功的。一個很普遍的情況是一個讀試圖不會完全失敗也不會完全成功,它可能讀出請求數據的一部分字節,而不是全部字節。例如,當實際上只有512字節已經到達服務器時,用戶可能會試圖從一個網絡流上讀取1024字節,而其他字節仍然在傳送中,這些字節最終會到達服務器,但到達時卻已是不可以獲得的。因此,多字節讀取方法會返回實際讀取的字節數目。給個例子

byte[] input=new byte[1024];

int bytesRead=in.read(input);

代碼段試圖從InputStream in讀取1024字節到數組input中。但是,假如僅有512字節可以獲得,則這些字節就是將要讀取的全部字節,并且bytesRead值會設為512。但我們為了保證在實際上讀取到所有的字節,怎么辦?看

int bytesRead=0;

int byteToRead=1024;

byte[] input=new byte[byteToRead];

while(bytesRead<byteToRead){

       bytesRead+=in.read(input,bytesRead,byteToRead-bytesRead);

}

Ø         public int available() throws IOException

假如由于某種原因用戶不希望讀取數據,除非用戶想要的全部數據可以立即得到,這時候就可以用available()方法返回的字節數是能夠讀取的最小字節數,而在實際上可以讀取更多的字節,但是能夠讀取的字節數據至少與available()返回的字節數一樣多。

看例子

int bytesAvailable=in.available();

byte[] input=new byte[bytesAvailable];

int byteTead=in.read(input,0,bytesAvailable);

//其他代碼

這里我們可以斷言bytesRead正好等于bytesAvailable,但不能斷言bytesRead>0,因為available()返回0是有可能的。

流結束時:

available()返回0;

read(byte[] data,int offset,int length)通常返回-1;

       流沒有結束,可讀取字節數即available()得到的值為0時

read(byte[] data,int offset,int length)會忽略流的結束,返回0;

 

Ø         public long skip(long n) throws IOException

在極少數情況下,用戶可能希望跳過數據而不去讀取它們。Skip()方法就是實現這個功能的。這個方法在從文件讀取數據時較為有用,而在網絡連接流上則用處較小。因為網絡連接流是有序的而且通常很慢,因此讀取數據的耗時不會太多的超過跳過數據的耗時。文件可以隨機訪問,因此我們通過重定位文件指針就能簡單的實現數據的跳轉,而不是跳過每一個字節。

 

Ø         public void close() throws IOException

和輸出流一樣,程序利用完輸入流之后,就應該調用close()方法關閉該輸入流了(要記住啊)。該方法會釋放與輸入流有關的所有資源,如文件句柄和端口。一旦輸入流關閉,再從它讀取數據時會觸發IOException。但是,有些類型的流可能仍答應對對象進行一定的操作。例如,用戶通常不希望從java.security.DigestInputStream中獲取報文摘要,除非已經讀取了所有數據并且關閉了輸入流。

 

看到這里或許你還會問怎么還有三個方法沒有呢,對,還有三個不常用的方法

public void mark(int readAheadLimit)

public void reset() throws IOException

public boolean markSupported();

這些方法答應程序備份和重新讀取已經讀取過的數據。要實現這個功能,需要用mark()方法在輸入流中的當前位置作個標記,在以后的某點可以使用reset()方法重新將流定位到標記處,隨后的讀取將返回從標記初開始的數據。但是,從標記處到重新將流定位點不能任意長。重新定位到標記處之前答應讀取的字節數就是由mark()的變量readAheadLimit決定。多長就會觸發IOException,而且任何指定時刻,輸入流中只可以有一個標記,假如標記了第二個標記,就會覆蓋第一個標記了。其實標記和重新設置位置都是通過存儲從內部緩沖區中的標記位置讀出每一字節來實現。最麻煩的狀況是,并非所有輸入流都支持標記和重新設置位置的。所以在設置之前要用markSupported()方法檢測一下。

實際上不支持標記和重新設置位置的流多于支持它們的流。Elliotte Rusty Harold大師覺得這幾個方法設計的標準不高,將功能性與一個許多甚至可能是大部分子類都不可用的抽象超類結合是一個相當拙劣的想法。最好是將這三個方法放在不同的接口中。提供類似于markSupported()方法在運行時進行功能性檢測是較為傳統,非面向對象的解決方法。面向對象的方法將通過接口和類把該方法嵌入到面向對象系統中,從而在編譯時檢測所有的流。

Java.io中總是支持標記的輸入流:BufferedInputStream和ByteArrayInputStream。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 美女羞羞视频在线观看 | 在线播放中文 | xvideos korean| 天天操天天碰 | 男女污视频在线观看 | 女18一级大黄毛片免费女人 | av色先锋| 国产亚洲精彩视频 | 国产一级一国产一级毛片 | 成人精品一区二区 | 新久草在线视频 | 看一级大毛片 | 一级黄色免费大片 | 杏美月av| 鸳鸯谱在线观看高清 | 91精品国产91久久久 | 最近日本电影hd免费观看 | 中文字幕视频在线播放 | 狠狠操视频网站 | 亚洲国产综合在线观看 | 亚洲欧美日韩精品久久 | 在线高清中文字幕 | 亚洲午夜天堂吃瓜在线 | 久草欧美| 精品国产一区二区三区天美传媒 | 精品日韩欧美 | 欧美大电影免费观看 | 中文字幕在线播放第一页 | 一夜新娘第三季免费观看 | 国产午夜精品久久久久久免费视 | 精品小视频| 成人区一区二区 | 一区国产在线 | 毛片一区二区三区四区 | 中文字幕在线成人 | 亚洲免费高清 | 成人超碰 | 亚洲无av | 久久免费视频8 | 娇喘在线 | 一级看片免费视频 |