tags:

views:

6447

answers:

7

I was surprised to find today that I couldn't track down any simple way to write the contents of an input stream to an output stream in Java. Obviously, the byte buffer code isn't difficult to write, but I suspect I'm just missing something which would make my life easier (and the code clearer).

So, given an InputStream in and an OutputStream out, is there a simpler way to write the following?

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
}
+4  A: 

I think this will work, but make sure to test it... minor "improvement", but it might be a bit of a cost at readability.

byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
    out.write(buffer, 0, len);
}
Mike Stone
I suggest a buffer of at least 10KB to 100KB. That's not much and can speed up copying large amounts of data tremendously.
Aaron Digulla
+5  A: 

It's a bit surprising that the libraries don't come with something like:

pipe(in, out);

Seems you're not the only one with that idea.

Apocalisp
This is awfully slow! Always copy at least 10KB or more in per iteration.
Aaron Digulla
Premature optimization is the root of all evil. ;)
Apocalisp
Jakarta Taglibs has been retired. http://jakarta.apache.org/taglibs/doc/io-doc/So I would suggest to use org.apache.commons.io.IOUtils, like Mikezx6r.
Fabien
+1  A: 

PipedInputStream and PipedOutputStream may be of some use, as you can connect one to the other.

Arktronic
+4  A: 

There's no way to do this a lot easier with JDK methods, but as Apocalisp has already noted, you're not the only one with this idea: You could use IOUtils from Jakarta Commons IO, it also has a lot of other useful things, that IMO should actually be part of the JDK...

WMR
+17  A: 

As WMR mentioned, IOUtils from apache has a method called copy which does exactly what you're looking for.

So, you have

IOUtils.copy(in,out);
in your code.

Is there a reason you're avoiding IOUtils?

Mikezx6r
+2  A: 

The new NIO package (in the JDK) abstracts this a bit with the new transferFrom and transferTo methods. The following snippet uses Files but you could adapt it to use streams and name it "copyStream".

public static void copyFile(File sourceFile, File destFile) throws IOException {
 FileChannel source = null;
 FileChannel destination = null;
 try {
  source = new FileInputStream(sourceFile).getChannel();
  destination = new FileOutputStream(destFile).getChannel();
  destination.transferFrom(source, 0, source.size());
 }
 finally {
  if(source != null) {
   source.close();
  }
  if(destination != null) {
   destination.close();
  }
}
Josh
A: 

PipedInputStream and PipedOutputStream should only be used when you have multiple threads, as noted by the javadoc.

Also note that input streams and output streams do not wrap any thread interruptions with IOExceptions... So you should consider incorporating an interruption policy to your code:

byte[] buffer = new byte[1024];
int len = in.read(buffer);
while (len != -1) {
    out.write(buffer, 0, len);
    len = in.read(buffer);
    if (Thread.interrupted()) {
        throw new InterruptedException();
    }
}

This would be an useful addition if you expect to use this API for copying large volumes of data, or data from streams that get stuck for an intolerably long time.

Dilum Ranatunga