Connecting an Input Stream to an Outputstream

Easy way to write contents of a Java InputStream to an OutputStream

Java 9

Since Java 9, InputStream provides a method called transferTo with the following signature:

public long transferTo(OutputStream out) throws IOException

As the documentation states, transferTo will:

Reads all bytes from this input stream and writes the bytes to the
given output stream in the order that they are read. On return, this
input stream will be at end of stream. This method does not close
either stream.

This method may block indefinitely reading from the
input stream, or writing to the output stream. The behavior for the
case where the input and/or output stream is asynchronously closed, or
the thread interrupted during the transfer, is highly input and output
stream specific, and therefore not specified

So in order to write contents of a Java InputStream to an OutputStream, you can write:

input.transferTo(output);

How to connect a input stream to a output stream in Java?

Guava and Apache Commons have copy methods:

ByteStreams.copy(input, output);

IOUtils.copy(input ,output);

They don't "connect" them directly. To achieve what I am assuming you want, create an InputStream decorator class that writes to an OutputStream everything that is read.

Most efficient way to create InputStream from OutputStream

If you don't want to copy all of the data into an in-memory buffer all at once then you're going to have to have your code that uses the OutputStream (the producer) and the code that uses the InputStream (the consumer) either alternate in the same thread, or operate concurrently in two separate threads. Having them operate in the same thread is probably much more complicated that using two separate threads, is much more error prone (you'll need to make sure that the consumer never blocks waiting for input, or you'll effectively deadlock) and would necessitate having the producer and consumer running in the same loop which seems way too tightly coupled.

So use a second thread. It really isn't that complicated. The page you linked to had reasonable example. Here's a somewhat modernized version, which also closes the streams:

try (PipedInputStream in = new PipedInputStream()) {
new Thread(() -> {
try (PipedOutputStream out = new PipedOutputStream(in)) {
writeDataToOutputStream(out);
} catch (IOException iox) {
// handle IOExceptions
}
}).start();
processDataFromInputStream(in);
}

How to convert OutputStream to InputStream?

An OutputStream is one where you write data to. If some module exposes an OutputStream, the expectation is that there is something reading at the other end.

Something that exposes an InputStream, on the other hand, is indicating that you will need to listen to this stream, and there will be data that you can read.

So it is possible to connect an InputStream to an OutputStream

InputStream----read---> intermediateBytes[n] ----write----> OutputStream

As someone metioned, this is what the copy() method from IOUtils lets you do. It does not make sense to go the other way... hopefully this makes some sense

UPDATE:

Of course the more I think of this, the more I can see how this actually would be a requirement. I know some of the comments mentioned Piped input/ouput streams, but there is another possibility.

If the output stream that is exposed is a ByteArrayOutputStream, then you can always get the full contents by calling the toByteArray() method. Then you can create an input stream wrapper by using the ByteArrayInputStream sub-class. These two are pseudo-streams, they both basically just wrap an array of bytes. Using the streams this way, therefore, is technically possible, but to me it is still very strange...

Best way to Pipe InputStream to OutputStream

I would say a fixed buffer size is the best/easiest to understand. However there are a few problems.

  • You're writing the entire buffer to the output stream each time. For the final block the read may have read < 1024 bytes so you need to take this into account when doing the write (basically only write number of bytes returned by read()

  • In the dynamic buffer case you use available(). This is not a terribly reliable API call. I'm not sure in this case inside a loop whether it will be ok, but I wouldn't be suprised if it was implemented sub-optimally in some implementations of InputStream.

  • The last case you are casting to FileInputStream. If you intend for this to be general purpose then you can't use this approach.

connect OutputStream with an InputStream

Abstract/decorate the Request as well and get the Response from it instead.

E.g. in your front controller servlet:

protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Request request = new RequestImpl(req, res);
Action action = ActionFactory.getAction(req); // Do whatever way you do to locate the `Action`.
Response = action.get(request);
// ...
}

wherein RequestImpl look like this:

public class RequestImpl implements Request {
private HttpServletRequest request;
private HttpServletResponse response;

public RequestImpl(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}

public Response newResponse(Status status) {
return new ResponseImpl(response, status);
// Add a boolean responseCreated to avoid creation of multiple responses? Illegal state!
}

public String getParameter(String name) { // Just another example of decorated method.
return request.getParameter(name);
}

// ...
}

and the ResponseImpl look like this:

public class ResponseImpl implements Response {
private HttpServletResponse response;

public ResponseImpl(HttpServletResponse response, Status status) {
this.response = response;
this.response.setStatus(status.getCode());
}

public OutputStream getOutputStream() {
return response.getOutputStream();
}

// ...
}

which you finally use like this in your Action:

public ActionImpl implements Action {
public Response get(Request request) {
Response response = request.newResponse(OK);
response.getOutputStream().write("body");
return response;
}
}

Alternatively, you can also create a Context which takes both the HttpServletRequest and HttpServletResponse and pass that in instead of Request. That's also less or more what the average MVC framework does. E.g.

protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
Context context = new ContextImpl(req, res);
Action action = ActionFactory.getAction(req); // Do whatever way you do to locate the `Action`.
action.execute(context);
context.render(); // Do here whatever you'd initially to do with the obtained Response.
}

with

public ActionImpl implements Action {
public void execute(Context context) {
context.getResponseOutputStream().write("body");
}
}

That said, instead of reinventing, I'd suggest to have a look to existing API's as well. Depending on what you'd like to do, JSF, JAX-RS or JAX-WS might be what you're actually after. Unless this is for pure hobby purposes ;)

converting OutputStream into an InputStream

Use a java.io.FilterOutputStream to wrap the existing OutputStream. By overriding the write() method you can intercept output and do whatever you want with it, either send it somewhere else, modify it, or discard it completely.

As to your second question, you cannot change the sink of an OutputStream after the fact, i.e. cause previously written data to "move" somewhere else, but using a FilterOutputStream you can intercept and redirect any data written after you wrap the original `OutputStream.



Related Topics



Leave a reply



Submit