Java - Resetting InputStream

47,749

Solution 1

As written, you have no guarantees, because mark() is not required to report whether it was successful. To get a guarantee, you must first call markSupported(), and it must return true.

Also as written, the specified read limit is very dangerous. If you happen to be using a stream that buffers in-memory, it will potentially allocate a 2GB buffer. On the other hand, if you happen to be using a FileInputStream, you're fine.

A better approach is to use a BufferedInputStream with an explicit buffer.

Solution 2

It depends on the InputStream implementation. You can also think whether it will be better if you use byte[]. The easiest way is to use Apache commons-io:

byte[] bytes = IOUtils.toByteArray(inputSream);

Solution 3

You can't do this reliably; some InputStreams (such as ones connected to terminals or sockets) don't support mark and reset (see markSupported). If you really have to traverse the data twice, you need to read it into your own buffer.

Solution 4

Instead of trying to reset the InputStream load it into a buffer like a StringBuilder or if it's a binary data stream a ByteArrayOutputStream. You can then process the buffer within the method as many times as you want.

ByteArrayOutputStream bos = new ByteArrayOutputStream();

int read = 0;
byte[] buff = new byte[1024];
while ((read = inStream.read(buff)) != -1) {
    bos.write(buff, 0, read);
}
byte[] streamData = bos.toByteArray();

Solution 5

For me, the easiest solution was to pass the object from which the InputStream could be obtained, and just obtain it again. In my case, it was from a ContentResolver.

Share:
47,749

Related videos on Youtube

iMineLink
Author by

iMineLink

Passionate Engineer, Gamer and Programmer.

Updated on May 14, 2020

Comments

  • iMineLink
    iMineLink about 4 years

    I'm dealing with some Java code in which there's an InputStream that I read one time and then I need to read it once again in the same method.

    The problem is that I need to reset it's position to the start in order to read it twice.

    I've found a hack-ish solution to the problem:

    is.mark(Integer.MAX_VALUE);
    
    //Read the InputStream is fully
    // { ... }
    
    try
    {
        is.reset();
    }
    catch (IOException e)
    {
        e.printStackTrace();
    }
    

    Does this solution lead to some unespected behaviours? Or it will work in it's dumbness?

    • Sotirios Delimanolis
      Sotirios Delimanolis over 10 years
      It might fail in situations that the reading code will mark() it as well.
    • Cruncher
      Cruncher over 10 years
      You may be able to extend InputStream, override the mark method so that it can only be called once in an instance.
  • iMineLink
    iMineLink over 10 years
    That means that a BufferedInputStream can be traversed twice?
  • iMineLink
    iMineLink over 10 years
    The byte[] would be too heavy for me to alloc...I already tried things like that and on some Android devices i got a OOM...should I compress it? How can I in that case?
  • iMineLink
    iMineLink over 10 years
    As commented at the other similar answer, the byte[] would be too heavy for me to alloc...
  • stan
    stan over 10 years
    If you are using SocketInputStream, you can not use mark() to read it more than once. If you don't have enough memory to save the stream data as a byte array, you can try to redirect the InputStream data to a temporary file, and then you can read the data from that file, using BufferedInputStream ( which supports mark() ) or RandomAccessFile.
  • kdgregory
    kdgregory over 10 years
    @iMineLink - Yes, provided that you give it a large enough buffer. There's nothing that's going to magically store bytes without consuming memory. If that's an issue, you'll need to store the data in a local file (I'm assuming, based on other comments, that you're reading from a socket).
  • iMineLink
    iMineLink over 10 years
    My fault not to have well specified it: I'm reading from an InputStream returned by a getResourceAsStream(xyz) which I think acts as a FileInputStream. So I'll try wrapping it in a BufferedInputStream with explicit buffer size.