JavaIO流詳解——Java語言I/O輸入輸出流read()readFully()



要搞清楚read(byte[] b)和readFully(byte[] b)的區別,可以從以下方面着手分析:

1.代碼的具體實現

2.方法何時返回

3.字節是以什麼方式在網絡上傳輸的


1.read(byte[] b)調用read(byte[] b,0,b.length),其中的部分關鍵代碼如下

 

Java代碼 複製代碼 收藏代碼
  1. int c = read();//讀取字節流中的下一個字節  
  2.      if (c == -1) {  
  3.           return -1;  
  4.       }  
  5.       b[off] = (byte)c;  
  6.   
  7.       int i = 1;  
  8.       try {  
  9.           for (; i < len ; i++) {  
  10.               c = read();  
  11.               if (c == -1) {  
  12.                   break;  
  13.               }  
  14.               b[off + i] = (byte)c;  
  15.           }  
  16.       } catch (IOException ee) { }  
  17.       return i;  
  int c = read();//讀取字節流中的下一個字節
       if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) { }
        return i;
 

readFully(byte[] b)調用readFully(byte[] b,0,b.length),其中的部分關鍵代碼如下

 

Java代碼 複製代碼 收藏代碼
  1. int n = 0;  
  2.  while (n < len) {//該方法一直阻塞,直到讀取到字節數據緩衝區裝滿  
  3.      int count = in.read(b, off + n, len - n);  
  4.      if (count < 0)  
  5.          throw new EOFException();  
  6.      n += count;  
  7.  }  
  8.   
  9. //read(bytes[] b,int off,int len)中的關鍵代碼  
  10. int c = read();  
  11.  if (c == -1) {  
  12.      return -1;  
  13.  }  
  14.  b[off] = (byte)c;  
  15.   
  16.  int i = 1;  
  17.  try {  
  18.      for (; i < len ; i++) {  
  19.          c = read();  
  20.          if (c == -1) {  
  21.              break;  
  22.          }  
  23.          b[off + i] = (byte)c;  
  24.      }  
  25.  } catch (IOException ee) { }  
  26.  return i;  
       int n = 0;
        while (n < len) {//該方法一直阻塞,直到讀取到字節數據緩衝區裝滿
            int count = in.read(b, off + n, len - n);
            if (count < 0)
                throw new EOFException();
            n += count;
        }

       //read(bytes[] b,int off,int len)中的關鍵代碼
       int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) { }
        return i;
 

 


2.從以上代碼,我們可以看到,read(byte[] b)一直阻塞等待讀取字節,直到字節流中的數據已經全部讀完。而readFully(byte[] b)是當數據緩衝區的空間還有剩餘時會阻塞等待讀取,直到裝滿。


3.下圖反映了字節流數據是如何通過網絡的

TCP報文傳送圖

應用程序用輸出流將數據輸入TCP的發送緩存中,這些數據被分割成TCP認爲最適合發送的數據塊(報文段或段)。報文段通過網絡的傳輸到達指定地址(URL)的TCP接收緩存中,接收到的報文段很有可能不是順序到達的,但TCP可以根據報文段的序號進行排序並存儲在TCP接收緩存中。應用程序如果需要獲得這些數據,需要通過輸入流讀取並解析這些報文段。



通過分析以上三個問題,我們可以解釋以下代碼存在的問題:

 

Java代碼 複製代碼 收藏代碼
  1. //發送端:  
  2. OutputStream out = ......;//通過TCP連接得到輸出流對象  
  3. String content = "...";  
  4. byte[] data = content.getBytes();  
  5. output.write(data);  
  6. int len = data.length;  
  7. while (len++ < 30) {  
  8.     output.writeByte('\0');//補夠30個字節  
  9. }  
  10. //接收端:    
  11. InputStream in = ......;//通過TCP連接得到輸入流對象  
  12. byte[] bytes = new byte[30];  
  13. in.read(bytes);  
//發送端:
OutputStream out = ......;//通過TCP連接得到輸出流對象
String content = "...";
byte[] data = content.getBytes();
output.write(data);
int len = data.length;
while (len++ < 30) {
	output.writeByte('\0');//補夠30個字節
}
//接收端:	
InputStream in = ......;//通過TCP連接得到輸入流對象
byte[] bytes = new byte[30];
in.read(bytes);
 

由於字節數據是在網絡中通過TCP連接進行傳輸,這些數據剛剛到達接收端(存儲在TCP接收緩衝區)的可能只是其中的一部分數據,其他的數據可能還在傳輸中甚至在發送端的TCP緩存中。在調用read(byte[] b)讀取數據時,b中得到的就是發出的30個字節的一部分。

要想完全獲得這30個字節數據,合理的方法是用readFully(byte[] b)讀取,因爲該方法會一直阻塞等待,直到30個數據全部到達(數據緩衝區裝滿)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章