I looked around online at InputStreams and it seems that you can only define an InputStream with a pre-defined input that it will read from. What if I wanted an InputStream where we're not sure what the data looks like or how long it is but it's generated somewhere on the fly but when it's done will return zero bytes in the end?
What I mean by pre-defined is that most constructors take in something you've already defined to read from (ex: ByteArrayInputStream(byte[] array), FileInputStream(File file))
My use case here is that I have a method that returns a certain amount of data (this methods calls the service an unknown amount of time and I want to stream this data as it's being generated on the fly)
Though you cannot convert an OutputStream to an InputStream, java provides a way using PipedOutputStream and PipedInputStream that you can have data written to a PipedOutputStream to become available through an associated PipedInputStream.
There is no real difference. FileInputStream extends InputStream , and so you can assign an InputStream object to be a FileInputStream object. In the end, it's the same object, so the same operations will happen. This behavior is called Polymorphism and is very important in Object-Oriented Programming.
Since Java 7, you can do it in one line even without using any external libraries: Files. copy(inputStream, outputPath, StandardCopyOption.
Sure, just extend InputStream
and have it do whatever you wish. ByteArrayInputStream
does exactly this.
The InputStream
class is an abstract class. It contains definitions for all relevant methods, except for one:
public int read() throws IOException
The documentation says:
Reads the next byte of data from the input stream. The value byte is returned as an int in the range 0 to 255. If no byte is available because the end of the stream has been reached, the value -1 is returned.
So an example showing how to create an input stream from an "arbitrary" data source could look like this:
import java.io.IOException;
import java.io.InputStream;
import java.util.function.IntSupplier;
public class DynamicInputStreamExample
{
public static void main(String[] args) throws IOException
{
IntSupplier supplier = () -> methodThatProvidesTheData();
InputStream inputStream = createStream(supplier);
while (true)
{
int read = inputStream.read();
System.out.println("Read " + read + " from stream");
if (read == -1)
{
break;
}
}
}
private static InputStream createStream(IntSupplier supplier)
{
return new InputStream()
{
@Override
public int read() throws IOException
{
return supplier.getAsInt();
}
};
}
// Dummy implementation of a method that provides the data,
// as a sequence of 6 bytes. It returns -1 if no more data
// is available.
private static final int data[] = { 'H', 'e', 'l', 'l', 'o' };
private static int index = 0;
private static int methodThatProvidesTheData()
{
if (index >= data.length)
{
return -1;
}
return data[index++];
}
}
Note: Depending on how your data is generated, it may be beneficial to additionally override other methods of the InputStream
class. Particularly, the read(byte[] b, int off, int len)
method that reads an array of bytes from the source. The main benefit of this would be that your could achieve a (much) higher performance when reading multiple bytes at once. But when this is not relevant for you, then just overriding the int read()
method is sufficient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With