如何在不读取 InputStream 的情况下检查 InputStream 是不是为空?

Posted

技术标签:

【中文标题】如何在不读取 InputStream 的情况下检查 InputStream 是不是为空?【英文标题】:How can I check if an InputStream is empty without reading from it?如何在不读取 InputStream 的情况下检查 InputStream 是否为空? 【发布时间】:2010-12-04 04:52:13 【问题描述】:

我想知道InputStream 是否为空,但没有使用read() 方法。有没有办法不读取就知道它是否为空?

【问题讨论】:

定义“空”。你的意思是“在流结束时”还是“没有数据可以在没有阻塞的情况下读取”? 【参考方案1】:

不读书是做不到的。但您可以使用如下解决方法。

您可以使用mark() 和reset() 方法来执行此操作。

mark(int readlimit) 方法标记此输入流中的当前位置。

reset() 方法将此流重新定位到最后一次在此输入流上调用标记方法时的位置。

在您可以使用标记和重置之前,您需要测试您正在读取的输入流是否支持这些操作。您可以使用 markSupported 做到这一点。

mark 方法接受一个限制(整数),它表示要提前读取的最大字节数。如果您阅读超过此限制,则无法返回此标记。

要将此功能应用于此用例,我们需要将位置标记为 0,然后读取输入流。在那里,我们需要重置输入流,输入流将恢复为原始流。

    if (inputStream.markSupported()) 
          inputStream.mark(0);
          if (inputStream.read() != -1) 
               inputStream.reset();
           else 
               //Inputstream is empty
          
    

如果输入流为空,则 read() 方法将返回 -1。

【讨论】:

【参考方案2】:

用inputStreamReader.ready()查一下怎么样?

import java.io.InputStreamReader;

/// ...

InputStreamReader reader = new InputStreamReader(inputStream);
if (reader.ready()) 
    // do something


// ...

【讨论】:

这不适用于所有 InputStream 子类;特别是,我无法让它为 GZIPInputStream 工作。我会冒险猜测它是使用 available() 实现的,这似乎也不适用于 GZIPInputStream。 问题是关于InputStream,而不是Reader 来自docs "判断该流是否已准备好被读取。如果 InputStreamReader 的输入缓冲区不为空,或者是否可以从底层字节流中读取字节,则该 InputStreamReader 已准备好。 "感谢您的建议。【参考方案3】:
public void run() 
    byte[] buffer = new byte[256];  
    int bytes;                      

    while (true) 
        try 
            bytes = mmInStream.read(buffer);
            mHandler.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget();
         catch (IOException e) 
            break;
        
    

【讨论】:

用这个替换run()。【参考方案4】:

如果您使用的 InputStream 支持标记/重置支持,您还可以尝试读取流的第一个字节,然后将其重置为原始位置:

input.mark(1);
final int bytesRead = input.read(new byte[1]);
input.reset();
if (bytesRead != -1) 
    //stream not empty
 else 
    //stream empty
 

如果你不控制你正在使用哪种InputStream,你可以使用markSupported()方法来检查标记/重置是否会在流上起作用,然后回退到available()方法或者java.io.PushbackInputStream 方法,否则。

【讨论】:

读取调用会阻塞,直到您获得输入,所以根据我的经验,这总是表明流不是空的(除非遇到流的结尾) 我必须为临时文件读取执行此操作,并且效果很好(我使用BufferedReader 来确保它支持标记/重置而无需对其进行测试) 该问题明确指出“不使用方法read()”和“不读取它”。 @EJP:这可能是它在 2009 年仅获得 5 次赞成票的原因。打哈欠。 不管它有多少票,它仍然是错误的。 bytesRead 只会在对等方断开连接时为 -1。这与“空”不同。【参考方案5】:

我想你正在寻找inputstream.available()。它不会告诉你它是否为空,但它可以告诉你是否有数据可以读取。

【讨论】:

available() 告诉你是否有数据准备好读取,它不一定告诉你流是否为空。 @skaffman:非常感谢!我认为这就足够了:)。编辑了我的答案以反映它。 available() 并没有完全满足我的需要,但它是最接近的解决方案。 “没有完全满足我的需要”你实际上需要什么?是在加载之前分配一个缓冲区,还是...? 为答案投票。用于命名的 boo java 可用,它看起来应该是布尔值,而不是 int。【参考方案6】:

根据使用 PushbackInputStream 的建议,您可以在这里找到一个示例实现:

/**
 * @author Lorber Sebastien <i>(lorber.sebastien@gmail.com)</i>
 */
public class NonEmptyInputStream extends FilterInputStream 

  /**
   * Once this stream has been created, do not consume the original InputStream 
   * because there will be one missing byte...
   * @param originalInputStream
   * @throws IOException
   * @throws EmptyInputStreamException
   */
  public NonEmptyInputStream(InputStream originalInputStream) throws IOException, EmptyInputStreamException 
    super( checkStreamIsNotEmpty(originalInputStream) );
  


  /**
   * Permits to check the InputStream is empty or not
   * Please note that only the returned InputStream must be consummed.
   *
   * see:
   * http://***.com/questions/1524299/how-can-i-check-if-an-inputstream-is-empty-without-reading-from-it
   *
   * @param inputStream
   * @return
   */
  private static InputStream checkStreamIsNotEmpty(InputStream inputStream) throws IOException, EmptyInputStreamException 
    Preconditions.checkArgument(inputStream != null,"The InputStream is mandatory");
    PushbackInputStream pushbackInputStream = new PushbackInputStream(inputStream);
    int b;
    b = pushbackInputStream.read();
    if ( b == -1 ) 
      throw new EmptyInputStreamException("No byte can be read from stream " + inputStream);
    
    pushbackInputStream.unread(b);
    return pushbackInputStream;
  

  public static class EmptyInputStreamException extends RuntimeException 
    public EmptyInputStreamException(String message) 
      super(message);
    
  


这里有一些通过测试:

  @Test(expected = EmptyInputStreamException.class)
  public void test_check_empty_input_stream_raises_exception_for_empty_stream() throws IOException 
    InputStream emptyStream = new ByteArrayInputStream(new byte[0]);
    new NonEmptyInputStream(emptyStream);
  

  @Test
  public void test_check_empty_input_stream_ok_for_non_empty_stream_and_returned_stream_can_be_consummed_fully() throws IOException 
    String streamContent = "HELLooooô wörld";
    InputStream inputStream = IOUtils.toInputStream(streamContent, StandardCharsets.UTF_8);
    inputStream = new NonEmptyInputStream(inputStream);
    assertThat(IOUtils.toString(inputStream,StandardCharsets.UTF_8)).isEqualTo(streamContent);
  

【讨论】:

该问题明确指出“不使用方法read()”和“不从中读取”。 @EJP 从概念上讲,如果您没有关于该流的任何其他相关信息(例如在 HTTP 流上 Content-Size标头。所以也许我们可以假设提问者理解这一点,并且只想检查流是否为空,同时仍然能够从头开始读取它。 我完全同意,但这是问题中指定的限制条件,他也没有回应关于他定义“空”的请求。【参考方案7】:

不,你不能。 InputStream 设计用于处理远程资源,因此在实际读取它之前您无法知道它是否存在。

但是,您可以使用java.io.PushbackInputStream,它允许您从流中读取内容以查看其中是否存在某些内容,然后将其“推回”到流中(实际上并非如此,但这就是它对客户端代码的行为方式)。

【讨论】:

PushbackInputStream 似乎是最可靠的解决方案,如果您不知道您正在处理哪种类型的流(即您有一个将 InputStream 作为参数的方法)。 检查我对基于实现的 PushbackInputStream 的回答:***.com/a/19137900/82609 正如InputStream.available() 的android SDK 文档中提到的“类InputStream 的可用方法总是返回0。这个方法应该被子类覆盖。”这隐含地告诉你在InputStream 实例上调用available() 方法实际上不会返回任何有意义的东西。 @Eido95 InputStream 是抽象的,因此所有实例都是子类的实例(根据文档,应该覆盖该方法)。【参考方案8】:

您可以使用available() 方法询问流是否有可用的数据在您调用它的那一刻。但是,不能保证该函数适用于所有类型的输入流。这意味着您不能使用available() 来确定对read() 的调用是否会真正阻塞。

【讨论】:

请告诉我一个available()不能正常工作的情况。 InputStream本身的available()方法默认返回0;如果子类不覆盖此方法,则将始终返回 0。 ...我知道它不适用于 SSL 套接字,但对我来说不是这样。 是的,我知道默认返回0,但是在Javadoc中,InputStream类的所有子类都有方法available()覆盖超类中的方法,并返回可用的字节数流。 @JennySmith 这根本不是真的。大多数available() 方法的Javadoc 只是声明它返回in.available(),,不管它可能做什么。 DataInputStream 甚至根本没有实现 available()PushbackInputStream.available() 仅保证在数据被推回时返回非零值。 StringBufferInputStream 是我能找到的唯一一个绝对总是能够返回非零值的。

以上是关于如何在不读取 InputStream 的情况下检查 InputStream 是不是为空?的主要内容,如果未能解决你的问题,请参考以下文章

如何在不打开领域文件的情况下检查我的领域架构版本?

在不移动文件指针的情况下检查文件指针是不是已达到 EOF?

如何在不接触缓存的情况下写入或读取内存

如何在不检查 MySQL 中的 AUTOINCREMENT 的情况下增加主键

如何在不检查路径扩展名的情况下检查文件是不是为图像文件?

如何在不提取Java的情况下读取压缩文件的内容