If you have several Java InputStreams that you want to queue up into a single InputStream object, you can use this:
- package com.varaneckas;
- import java.io.IOException;
- import java.io.InputStream;
- import java.util.LinkedList;
- /**
- * {@link InputStream} implementation that allows chaining of various
- * streams for seamless sequential reading
- *
- * @author Tomas Varaneckas <tomas.varaneckas@gmail.com>
- */
- public class InputStreamChain extends InputStream {
- /**
- * Input stream chain
- */
- private final LinkedList<InputStream> streams = new LinkedList<InputStream>();
- /**
- * Currently active stream
- */
- private InputStream current;
- /**
- * Default constructor
- */
- public InputStreamChain() {
- //nothing to do
- }
- /**
- * Constructor with an initial stream
- *
- * @param first Initial InputStream
- */
- public InputStreamChain(final InputStream first) {
- addInputStream(first);
- }
- /**
- * Constructor with an array of initial streams
- *
- * @param streams Array of initial InputStreams
- */
- public InputStreamChain(final InputStream[] streams) {
- for (InputStream stream : streams) {
- addInputStream(stream);
- }
- }
- /**
- * Vararg constructor
- *
- * @param streams initial input streams
- */
- public InputStreamChain(final InputStream ... streams) {
- for (InputStream stream : streams) {
- addInputStream(stream);
- }
- }
- /**
- * Adds input stream to the end of chain
- *
- * @param stream InputStream to add to chain
- * @return instance of self (for fluent calls)
- */
- public InputStreamChain addInputStream(final InputStream stream) {
- streams.addLast(stream);
- if (current == null) {
- current = streams.removeFirst();
- }
- return this;
- }
- @Override
- public int read() throws IOException {
- int bit = current.read();
- if (bit == -1 && streams.size() > 0) {
- try {
- current.close();
- } catch (final IOException e) {
- //replace this with a call to logging facility
- e.printStackTrace();
- }
- current = streams.removeFirst();
- bit = read();
- }
- return bit;
- }
- @Override
- public int available() throws IOException {
- int available = current.available();
- for (InputStream stream : streams) {
- available += stream.available();
- }
- return available;
- }
- @Override
- public void close() throws IOException {
- current.close();
- }
- @Override
- public boolean markSupported() {
- return current.markSupported();
- }
- @Override
- public synchronized void mark(int i) {
- current.mark(i);
- }
- @Override
- public synchronized void reset() throws IOException {
- current.reset();
- }
- @Override
- public long skip(long l) throws IOException {
- return current.skip(l);
- }
- }
Example code:
- InputStream chuck = new ByteArrayInputStream("Chuck ".getBytes());
- InputStream norris = new ByteArrayInputStream("Norris".getBytes());
- InputStream chuckNorris = new InputStreamChain()
- .addInputStream(chuck)
- .addInputStream(norris);
- //will print "Chuck Norris"
- System.out.println(new BufferedReader(
- new InputStreamReader(chuckNorris)).readLine());
Have fun!
Cool, I can see how that can be handy! But why not use vararg and allow links in the chain to be added through the constructor? Method chaining introduces mutability and a wider, more complex state space that I don't see is necessary here.
ReplyDeletejava.io.SequenceInputStream?
ReplyDelete@casper bang
ReplyDeleteYeah, I guess you're right, haven't thought of adding vararg constructor in first place. I'll update the source.
@phloser
Damn, I knew there would be something like this done already, but I was doing this in a hurry and a quick research gave me no results so it was faster to roll my own... Anyway, I decompiled and looked at java.lang.SequenceInputStream implementation. It looks old and somewhat cumbersome, with Enumeration in the constructor, etc.
No matter what, it was fun writing my own class. :)