要搞清楚read(byte[] b)和readFully(byte[] b)的區別,可以從以下方面着手分析:
1.代碼的具體實現
2.方法何時返回
3.字節是以什麼方式在網絡上傳輸的
1.read(byte[] b)調用read(byte[] b,0,b.length),其中的部分關鍵代碼如下
- 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;
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),其中的部分關鍵代碼如下
- 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;
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認爲最適合發送的數據塊(報文段或段)。報文段通過網絡的傳輸到達指定地址(URL)的TCP接收緩存中,接收到的報文段很有可能不是順序到達的,但TCP可以根據報文段的序號進行排序並存儲在TCP接收緩存中。應用程序如果需要獲得這些數據,需要通過輸入流讀取並解析這些報文段。
通過分析以上三個問題,我們可以解釋以下代碼存在的問題:
- //發送端:
- 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);
//發送端:
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個數據全部到達(數據緩衝區裝滿)