深入理解read(byte[] b)与readFully(byte[] b)

要搞清楚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个数据全部到达(数据缓冲区装满)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值