Socket 中的 InputStream

无论文件读取还是Socket通信,都要操作流。Java为我们提供了InputStream和OutputStream的IO库,从数据流InputStream中读取数据时,有三种读取的方法,方法二、三本质是一样的。三种方法都返回int型,同时能够抛出IOException异常

  • read()
  • read(byte[] b)
  • read(byte[] b, int off, int len)

read()

从输入流读取下一个字节,读取的返回值为该字节的int值(0~255)。如果读到流的末尾,返回-1。方法会一直阻塞直到读取到一个字节,或到达流末尾,或抛出异常

逐个字节的读取,效率太低了

read(byte[] b)

从输入流字节到缓冲数组b中。如果b=0,读取0字节并返回0;如果b!=0,b.length代表字节缓冲区的大小,我们只知道至少能读取1字节。如果读到流的末尾,返回-1。方法会一直阻塞直到从流中读取到字节,或到达流末尾,或抛出异常

该方法等价于方法三read(byte[] b, 0, b.length),因此两种方法都需要注意,方法仅限定了缓冲区的长度,即最大能读取长度,每次真正能读多少字节,是不确定的。这种方式使我们在读取流时,可能会出现缓冲足够大,却没有一次性读完流/文件的问题。在 慎用InputStream的read()方法 一文中,作者通过编程测试,发现“在大多数情况下,我们能够用read(b, readBytes, 22480-readBytes)一次性就读完整个文件,但还是有极少数情况,我们需要两次甚至两次以上调用该方法才能把整个文件读完”。因此,在使用read方法的时候,必须考虑在数据流没有到达文件末尾的情况下,读满自己想要的字节。上文作者也给出了解决方法


close()

是否关闭流?

我写过一个Socket的长连接的程序,client一直保持运行,至少6s就会有一次和server的通信,读取server发送过来的大量数据,client的inputStream也一直没有close,Socket就这么好好的正常工作了…而且有谁能告诉我为什么 javadoc-java官方文档 中close()方法的说明是“关闭input stream和释放与该流相关的系统资源。The close method of InputStream does nothing!!!”does nothing啊!!!nothing是什么意思!!!

因为是长连接,要持续使用输入输出流,就没有关闭。client在读完一批又一批流后继续阻塞在-1等待下一批数据。如果真把流关了,Socket也就断了。

ByteArrayOutputStream

从InputStream中获取了流后,并不能直接读取inputStream中的数据,即使read到buffer里,也不能直接buffer.toString(),必须要对buffer内的报文进行转码。因此,Java为我们提供了ByteArrayOutputStream类,将内存中的数据读到字节数组中,转码后又以流的方式读出,实现了对一个字节数组的读入-转码-读出操作。javadoc-java官方文档 里给出了对该类的说明:

This class implements an output stream in which the data is written into a byte array. The buffer automatically grows as data is written to it. The data can be retrieved using toByteArray() and toString().

ByteArrayOutputStream类继承自output stream,将流写入byte数组。缓冲数组长度随着数据的写入自动增长。数据可以通过toByteArray()和toString()的方法读取。


Socket 长连接中的 InputStream

PO出这段Socket长连接的代码,以后学会了更好的写法,会再PO出来对比的

public void receiveMessage(Socket socket) throws IOException {
    String receive = "";
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(64000);
    byte[] buffer = new byte[12800];
    int length; 
    InputStream inputStream = client.getInputStream();

    // read()会一直阻塞
    while((length = inputStream.read(buffer)) != -1) {
        byteArrayOutputStream.write(buffer, 0, length);
        // 转码后读取数据
        receive = byteArrayOutputStream.toString("UTF-8");
        byteArrayOutputStream = new ByteArrayOutputStream();
    }
}

仓促地完成了项目,回头才明白这段代码涉及的内容:

  • read()会一直阻塞到流中有数据,读到流末尾return -1
  • 即使read到了流末尾,方法也会一直阻塞在-1等待流内新的数据,这也是receiveMessage能一直运行接收消息的原因
  • 按理说流不用了都是要close(虽然我没有close程序一样能运行…但是close也有close的要求,JDK的SocketInputStream和SocketOutputStream的close方法 以及 Socket的shutdownInput和shutdownOutput是干嘛用的?中就提到了关闭流时应该考虑的情况,放在后面的文章中写吧(这里应当mark一个将来文章的链接haha)
  • Inputstream和OutputStream在不需要时最好close,那么ByteArrayOutputStream是否也要close呢?答案是不需要!

    Closing a ByteArrayOutputStream/InputStream has no effect.

    关于ByteArrayOutputStream和ByteArrayInputStream的应用,包括方法的实质,close的实现,应用的优势等都足以再写一篇文章了(这里也应该mark一个将来文章的链接hahaha)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值