【问题标题】:A better way to find out how many bytes are in a stream?找出流中有多少字节的更好方法?
【发布时间】:2013-08-26 19:33:17
【问题描述】:

目前,我依靠ObjectInputStream.available() 方法告诉我一个流中还剩下多少字节。原因——我正在对某些处理流的函数编写一些单元/集成测试,我只是想确保available() 方法在我完成后返回 0。

不幸的是,在测试失败时(即,我已经在流中发送了大约 8 个字节),我对 available() == 0 的断言在它应该为假的时候出现了。它应该显示 >0 或 8 个字节!

我知道 available() 方法在经典上是不可靠的,但我认为它至少会显示 > 0!

是否有更可靠的方法来检查流是否为空(毕竟这是我的主要目标)?也许在 Apache IO 域或其他一些库中?

有人知道为什么available() 方法如此不可靠吗?有什么意义呢?或者,有没有特定的、正确的使用方法?


更新:

所以,正如你们中的许多人可以从 cmets 中看到的那样,我面临的主要问题是,在流的一端,我发送了一定数量的字节,但在另一端,并非所有字节都到达!

具体来说,我在一端发送 205498 个字节,而在另一端只收到 204988 个字节,始终如一。我在套接字中的线程之间控制此操作的双方,但这应该没关系。

这是我为收集所有字节而编写的代码。

  public static int copyStream(InputStream readFrom, OutputStream writeTo, int bytesToRead)
      throws IOException {

    int bytesReadTotal = 0, bytesRead = 0, countTries = 0, available = 0, bufferSize = 1024 * 4;

    byte[] buffer = new byte[bufferSize];

    while (bytesReadTotal < bytesToRead) {

      if (bytesToRead - bytesReadTotal < bufferSize)
        buffer = new byte[bytesToRead - bytesReadTotal];

      if (0 < (available = readFrom.available())) {
        bytesReadTotal += (bytesRead = readFrom.read(buffer));
        writeTo.write(buffer, 0, bytesRead);
        countTries = 0;

      } else if (countTries < 1000)
        try {
          countTries++;
          Thread.sleep(1L);

        } catch (InterruptedException ignore) {}
      else

        break;
    }

    return bytesReadTotal;
  }

我把 countTries 变量放在那里只是为了看看会发生什么。即使没有 countTires,它也会在到达 BytesToRead 之前永远阻塞。

什么会导致流突然无限期阻塞?我知道在另一端它完全发送字节(因为它实际上使用相同的方法,我看到它完成了功能完整的 BytesToRead 最后匹配 bytesReadTotal。但接收器没有。事实上,当我查看数组时,它们也完全匹配到最后。

更新2

我注意到,当我在 copyStream 方法的末尾添加 writeTo.flush() 时,它似乎又可以工作了。嗯..为什么在这种情况下冲洗如此重要。即,为什么不使用它会导致流永久阻塞?

【问题讨论】:

  • 你怎么知道流中有x字节而不读取它? available() 方法明确声明返回可以不阻塞读取的字节数。如果要读取更多字节,则需要阻塞。
  • 您应该检查 InputStream#read() 返回 -1 以查看是否已到达流的末尾。
  • @SotiriosDelimanolis,available() 不应该至少给出一个返回值 1 以表明在阻塞时至少有 1 个字节要读取?
  • 如果它可以不阻塞地读取 1 个字节,它会这样说。 它不知道在没有读取它们的情况下阻塞时可以读取多少字节(即到达流的末尾)。
  • 我明白了……这很有趣。在我期望流中没有任何内容的情况下,我实际上正在读取一个字节 0x79,之后,.read() 方法会无限期阻塞......这些症状是否让您想起了什么?

标签: java apache stream streaming


【解决方案1】:

available() 方法只返回无阻塞可以读取多少字节(可能为0)。为了查看流中是否还有任何字节,您必须read()read(byte[]) 将返回读取的字节数。如果返回值为-1,则说明您已到达文件末尾。

这个小代码 sn-p 将循环通过 InputStream 直到它到达末尾(read() 返回 -1)。我认为它永远不会返回 0,因为它应该阻塞,直到它可以读取 1 个字节或发现没有什么可以读取(因此返回 -1)

int currentBytesRead=0;
int totalBytesRead=0;
byte[] buf = new byte[1024];

while((currentBytesRead =in.read(buf))>0){
        totalBytesRead+=currentBytesRead;

}

【讨论】:

  • 目前我正在使用这样的东西:int b; while ((b = singleServersT.getInputStream().read()) != -1) { System.err.print(b);但它实际上在第一个字节读取后阻塞!我在我原来的帖子中添加了关于这个新灯的 cmets。
  • 是的,您的代码也是如此。 TotalBytesRead == 1 在第一个循环之后,它会阻塞。
  • 它应该是阻塞的,你无法知道整个流中还有多少字节没有阻塞。
  • 嗯,你怎么能强制发送 EOF?
  • 对于测试,您可以模拟 InputStream 或返回一个包装 byte[] 的实例,例如 new ByteArrayInputStream(myBytes);它将在读取数组中的所有字节后发送 EOF。作为奖励,因为数组都在内存中,它也不会阻塞,所以 available() 将返回数组的长度
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-30
  • 2011-10-03
  • 1970-01-01
  • 1970-01-01
  • 2014-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多