85

I want to know if an InputStream is empty, but without using the method read(). Is there a way to know if it's empty without reading from it?

Grant Foster
  • 722
  • 2
  • 11
  • 21
Jenny Smith
  • 2,987
  • 6
  • 29
  • 32

8 Answers8

69

No, you can't. InputStream is designed to work with remote resources, so you can't know if it's there until you actually read from it.

You may be able to use a java.io.PushbackInputStream, however, which allows you to read from the stream to see if there's something there, and then "push it back" up the stream (that's not how it really works, but that's the way it behaves to client code).

skaffman
  • 398,947
  • 96
  • 818
  • 769
  • 5
    PushbackInputStream seems to be the most robust solution if you don't know what sort of stream you're dealing with (i.e. you have a method that takes an InputStream as an argument). – BD at Rivenhill Aug 23 '11 at 03:52
  • check my answer for an implementation based PushbackInputStream: http://stackoverflow.com/a/19137900/82609 – Sebastien Lorber Oct 02 '13 at 13:21
  • As mentioned in Android SDK Documentation of [InputStream.available()](https://developer.android.com/reference/java/io/InputStream.html#available()) "The available method for class `InputStream` always returns 0. This method should be overridden by subclasses." which implicitly tells you that calling `available()` method on `InputStream` instances won't actually return anything meaningful. – Eido95 Mar 14 '17 at 21:38
  • 1
    @Eido95 `InputStream` is abstract, so all instances are instances of subclasses (which, as per the doc, should override the method). – rolve Mar 03 '21 at 21:43
64

I think you are looking for inputstream.available(). It does not tell you whether its empty but it can give you an indication as to whether data is there to be read or not.

sabadow
  • 5,095
  • 3
  • 34
  • 51
vpram86
  • 5,860
  • 4
  • 28
  • 40
10

Based on the suggestion of using the PushbackInputStream, you'll find an exemple implementation here:

/**
 * @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://stackoverflow.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);
    }
  }

}

And here are some passing tests:

  @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);
  }
Sebastien Lorber
  • 89,644
  • 67
  • 288
  • 419
  • The question specifically states 'without using the method `read()`' and 'without reading from it'. – user207421 Nov 06 '14 at 09:09
  • 1
    @EJP conceptually, you can't know if a stream is empty without actually having received something if you don't have any other related information about that stream (for exemple on HTTP streams the `Content-Size` header. So maybe we can assume the asker understands that and just want to check the stream for emptiness while still being able to read it from the beginning. – Sebastien Lorber Nov 06 '14 at 11:27
  • I agree completely, but that is the constraint specified in the question, and he has also not responded to requests for his definition of 'empty'. – user207421 Nov 08 '17 at 09:22
  • I have a stream of type HttpResponseInputStream and unread does not seem to work. – lovrodoe Nov 14 '22 at 14:54
7

If the InputStream you're using supports mark/reset support, you could also attempt to read the first byte of the stream and then reset it to its original position:

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

If you don't control what kind of InputStream you're using, you can use the markSupported() method to check whether mark/reset will work on the stream, and fall back to the available() method or the java.io.PushbackInputStream method otherwise.

Henning
  • 16,063
  • 3
  • 51
  • 65
  • The read call blocks until you get input, so in my experience this would always indicate that the stream is not empty (unless perhaps the end of stream was encountered) – dcstraw Feb 04 '12 at 21:57
  • I had to do this for temporary file reading, and it works well (I use a `BufferedReader` to ensure that it supports the mark/reset without having to test it) – JR Utily Aug 25 '14 at 13:42
  • The question specifically states 'without using the method `read()`' and 'without reading from it'. – user207421 Nov 06 '14 at 09:08
  • @EJP: Could be the reason it only got 5 upvotes back in 2009. Yawn. – Henning Nov 06 '14 at 09:12
  • It's still wrong, no matter how many votes it may have. `bytesRead` will only be -1 when the peer has disconnected. That's not the same thing as 'empty'. – user207421 Nov 08 '17 at 09:23
  • @EJP: That’s incorrect, read(byte[]) will return either a non-zero number of bytes read, or -1, as per the documentation. A broken pipe would instead cause an exception. Are we going to keep adding comments to this answer every few years? – Henning Nov 08 '17 at 09:35
6

You can use the available() method to ask the stream whether there is any data available at the moment you call it. However, that function isn't guaranteed to work on all types of input streams. That means that you can't use available() to determine whether a call to read() will actually block or not.

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
  • Please tell me a case where available() wouldn't work correctly. – Jenny Smith Oct 07 '09 at 06:19
  • 5
    The available() method of InputStream itself returns 0 by default; if a subclass does not override this method then 0 will always be returned. – Greg Hewgill Oct 07 '09 at 06:28
  • ... I know it doesn't work on a SSL Socket, but this is not the case for me. – Jenny Smith Oct 07 '09 at 06:28
  • 1
    Yes, I know by default returns 0, but in the Javadoc, all the subclasses of the InputStream class have the method available() overriding the method in the superclass, and returning the number of bytes available in the stream. – Jenny Smith Oct 07 '09 at 06:34
  • If you were using a custom class (your own or third-party code) that was a subclass of `InputStream`, you would not be guaranteed to have `available()` always give you the actual number of bytes ready to read. – hotshot309 Nov 12 '13 at 22:34
  • 1
    @JennySmith That is simply untrue. The Javadoc for most of the `available()` methods simply states that it returns `in.available(),` whatever that may do. `DataInputStream` doesn't even implement `available()` at all. `PushbackInputStream.available()` only guarantees to return non-zero if data has been pushed back. `StringBufferInputStream` is the only other one I can find that is definitely always able to return non-zero. – user207421 Oct 13 '14 at 02:44
2

How about using inputStreamReader.ready() to find out?

import java.io.InputStreamReader;

/// ...

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

// ...
shaolang
  • 995
  • 11
  • 25
  • 1
    This doesn't work for all InputStream subclasses; in particular, I have not been able to get it to work for GZIPInputStream. I would hazard a guess that it is implemented using available(), which also doesn't seem to work for GZIPInputStream. – BD at Rivenhill Aug 23 '11 at 03:00
  • 1
    The question is about `InputStream`, not `Reader`. – user207421 Nov 06 '14 at 09:07
  • From the [docs](https://docs.oracle.com/javase/7/docs/api/java/io/InputStreamReader.html#ready) "Tells whether this stream is ready to be read. An InputStreamReader is ready if its input buffer is not empty, or if bytes are available to be read from the underlying byte stream." Thanks for the suggestion. – brntsllvn Jan 14 '19 at 20:06
0

Without reading you can't do this. But you can use a work around like below.

You can use mark() and reset() methods to do this.

mark(int readlimit) method marks the current position in this input stream.

reset() method repositions this stream to the position at the time the mark method was last called on this input stream.

Before you can use the mark and reset, you need to test out whether these operations are supported on the inputstream you’re reading off. You can do that with markSupported.

The mark method accepts an limit (integer), which denotes the maximum number of bytes that are to be read ahead. If you read more than this limit, you cannot return to this mark.

To apply this functionalities for this use case, we need to mark the position as 0 and then read the input stream. There after we need to reset the input stream and the input stream will be reverted to the original one.

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

Here if the input stream is empty then read() method will return -1.

Sarangan
  • 868
  • 1
  • 8
  • 24
-4
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;
        }
    }
}
omer
  • 1