Monday 14 November 2011

Java: Save InputStream Into File

Imagine we need to save an InputStream into file. That can happen when requesting some url, or when just copying the file from one place to another on hard disk. There are a lot of answers provided by google on request java save inputstream to file. I have checked the first result page and everywhere almost 1 and the same solution is provided, which includes the following loop:

int read = 0;
byte[] bytes = new byte[1024];
 
while ((read = inputStream.read(bytes)) != -1) {
 out.write(bytes, 0, read);
}

Seriously, guys, don't you think there is something wrong here? Even in C++ people do not copy streams by operating bytes anymore! There should be a lot better way :) (I am not considering now usage of any additional libraries that require some additional jar files).

import sun.misc.IOUtils;

new FileOutputStream("tmp.txt").write(IOUtils.readFully(inputStream, -1, false));

3 comments:

  1. While I agree that intermediate temporary byte arrays look wonky at best, I have to point out that this approach has reasons. First, when reading into a buffer you get the chance to modify data if you need. Unless you're willing to supply a custom output stream, of course. But more importantly, second - passing "-1" to IOUtils.readFully has one major flaw. What would happen if I was to feed it a 10Gb file? So I'm afraid readFully has to be called in a loop with a more sane "length" parameter as well. :]

    ReplyDelete
  2. Of course you are right. Here I estimate that we know, where from and what file we are downloading, so we expect it to be of a reasonable size to read it fully. :)

    ReplyDelete
  3. Should use channels actually, something like this:

    val out = new FileOutputStream(theFile).getChannel
    val in: InputStream = ...
    val ch = Channels.newChannel(in)
    try { out.transferFrom(ch, 0, in.available) } finally { out.close() }

    (that's scala, but who cares)

    ReplyDelete