根据 Java api 文档,在 InputStream 中声明的 read() 方法描述如下:如果由于已到达流末尾而没有可用的字节,则值为 -1
根据 Java api文档 , read()
中声明的 InputStream
描述如下:
如果由于已到达流末尾而没有可用的字节,则返回值 -1。此方法将阻塞,直到输入数据可用、检测到流末尾或引发异常。
我有一个 while(true)
循环 read()
,当流中没有发送任何内容时,我总是得到 -1。这是意料之中的。
我的问题是什么时候会 read()
阻塞?因为如果它没有收到任何数据,它会返回 -1。我期望阻塞 read()
会等到收到数据。如果您已经到达输入流的末尾,难道不应该 read()
只是等待数据而不是返回 -1 吗?
或者 read()
仅当有另一个线程访问该流而您 read()
无法访问该流时才会阻塞?
这就引出了我的下一个问题。我曾经有一个事件监听器(由我的库提供),当数据可用时它会通知我。当我收到通知时,我会开始 while((aByte = read()) > -1)
循环存储字节。当我在很短的时间内收到两个事件并且并非所有数据都显示出来时,我感到很困惑。似乎只有第二个事件的数据的尾部会显示出来,其余数据都丢失了。
我最终修改了我的代码,这样当我收到事件时,我就开始 if(inputStream.available() > 0) while((aByte = read()) > -1)
存储字节。现在它工作正常,我的所有数据都显示出来。
有人能解释一下这种行为吗? 的 available()
方法 InputStream
据说返回在阻止下一个调用者(流的调用者?)之前可以读取的字节数。 即使我不使用, available()
我也希望第一个事件的读取只会阻止第二个事件的读取,但不会擦除或消耗太多的流数据。 为什么这样做会导致我的数据无法全部显示?
是的!Jbu,不要放弃你的流。我们在这里谈论的是串行通信。对于串行的东西,绝对可以预期在读取时可以/将返回 -1,但仍期望稍后有数据。问题是大多数人习惯于处理 TCP/IP,除非 TCP/IP 断开连接,否则它应该始终返回 0... 那么是的,-1 是有道理的。但是,对于串行,长时间没有数据流,没有“HTTP 保持活动”或 TCP/IP 心跳,或者(在大多数情况下)没有硬件流控制。但链接是物理的,仍然通过“铜”连接,并且仍然完全处于活动状态。
现在,如果他们说的是正确的,即:串行应该在 -1 上关闭,那么为什么我们必须监视诸如 OnCTS、pmCarroerDetect、onDSR、onRingIndicator 等东西...哎呀,如果 0 表示它在那里,而 -1 表示它不存在,那么就把所有那些检测功能都搞砸了!:-)
您所面临的问题可能存在于其他地方。
现在来谈谈具体细节:
问:“好像只能显示第二个事件的数据的尾部,其余部分都丢失了。”
答:我猜你处于一个循环中,重复使用相同的 byte[] 缓冲区。第一条消息进来,尚未显示在屏幕/日志/std 输出上(因为你处于循环中),然后你读取第二条消息,替换缓冲区中的第一条消息数据。同样,因为我猜你没有存储你读了多少,然后确保将存储缓冲区偏移上一次读取的数量。
问:\'我最终修改了我的代码,以便当我收到一个事件时,我会调用 if(inputStream.available() > 0) while((aByte = read()) > -1) 来存储该字节。\'
答:太棒了……这真是个好东西。现在,您的数据缓冲区位于 IF 语句中,您的第二条消息不会破坏您的第一条消息……好吧,实际上,它可能一开始只是一条较大的消息。但现在,您将一次性读取所有内容,保持数据完整。
C:\'... 竞争条件 ...\'
A:啊,老套的替罪羊!竞争条件…… :-) 是的,这可能是竞争条件,事实上很可能是。但是,也可能只是 RXTX 清除标志的方式。清除“数据可用标志”可能不会像预期的那样快。例如,有人知道 read 和 readLine 在清除先前存储数据的缓冲区和重新设置事件标志方面的区别吗?我也不知道。 :-) 我也找不到答案……但是……让我再唠叨几句。事件驱动编程仍然存在一些缺陷。让我给你一个我最近不得不处理的真实例子。
瞧,通知被错过了,因为标志仍然被设置……即使我已经开始读取字节。如果我读完了字节,那么标志就会被清除,我就会收到接下来 10 个字节的通知。
这与您现在所发生的情况完全相反。
所以,是的,使用 IF available() ... 读取返回的数据长度。然后,如果您比较偏执,请设置一个计时器并再次调用 available(),如果那里仍有数据,则读取新数据。如果 available() 返回 0(或 -1),则放松...坐下来...等待下一个 OnEvent 通知。