16
ServletOutputStream output = response.getOutputStream();
output.write(byte[]);

What is the most effective way to write File to javax.servlet.ServletOutputStream?

EDIT:

won't this be more effective if the NIO was used?

IAdapter
  • 62,595
  • 73
  • 179
  • 242
  • nio is not a magic bullet which makes everything io based faster. in fact, nio is generally helpful if you need to make your code more _scalable_ (e.g. fewer threads handling more connections). for single threaded code, io is almost always as good or better (exception to this rule may be file to file transfer). – jtahlborn Jan 10 '11 at 13:08

4 Answers4

37
IOUtils.copy(in, out);
out.flush();
//...........
out.close(); // depends on your application

Where in is the FileInputStream and out is the SocketOutputStream. IOUtils is a utility from Commons IO module in Apache Commons.

Rob Hruska
  • 118,520
  • 32
  • 167
  • 192
AlexR
  • 114,158
  • 16
  • 130
  • 208
6

You have a ServletOutputStream. The only way you can write to that is via java.io.*. You can't use NIO on it at all (other than via wrapping with Channels, which is pointless: it's still an OutputStream underneath and you are just adding processing over the top). The actual I/O is network-bound, and your writes are being buffered anyway by the servlet container (so that it can set the Content-Length) header so looking for performance tweaks here is pointless.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 9
    @01: Yes, you can use NIO's channels if you use Channels.newChannel(OutputStream). Which wraps the output stream in a channel. It is still talking to an underlying ByteArrayOutputStream. There is no efficiency gain in this situation. It is pointless. – user207421 Jan 11 '11 at 09:05
  • @JerylCook I addessed that in comments **five and a half years ago** and have so far attracted 5 comment votes for having done so. Look. – user207421 Aug 12 '16 at 01:28
3

First of all, this is unrelated to servlets. This applies to Java IO in general. You have after all just an InputStream and an OutputStream.

As to the answer, you're not the only one who wondered about this. On the interwebs you can find others who wondered about the same but took the effort to test/benchmark it themselves:

In general, a FileChannel with a 256K byte array which is read through a wrapped ByteBuffer and written directly from the byte array is the fastest way. Indeed, NIO.

FileInputStream input = new FileInputStream("/path/to/file.ext");
FileChannel channel = input.getChannel();
byte[] buffer = new byte[256 * 1024];
ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);

try {
    for (int length = 0; (length = channel.read(byteBuffer)) != -1;) {
        System.out.write(buffer, 0, length);
        byteBuffer.clear();
    }
} finally {
    input.close();
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • The first link actually seems to recommend an 8K buffer since the time to copy difference between 8 and 256K is minimal. That seems to make sense given that most file systems still use 4KB pages and 4KB disk clusters. – AngerClown Jan 10 '11 at 14:19
  • Difference is indeed minimal. OP is however asking for "effective way" not "efficient way". 8K is still fast but less memory consuming in case of a busy site. – BalusC Jan 10 '11 at 14:24
  • What about using channels and Channel.transferTo ? – IAdapter Jan 10 '11 at 14:37
  • 1
    @IAdapter In general, using `transferTo()` will give the best performance; unfortunately, the Servlet API doesn't expose the `SocketChannel`, so the optimization isn't available. – erickson Apr 16 '13 at 18:47
  • where do you write it to an ServletOutputStream? – Yannick Mussche Jun 26 '23 at 13:45
-1

If you don't want to add that jar to your application then you have to copy it by hand. Just copy the method implementation from here: http://svn.apache.org/viewvc/commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1004358&view=markup:

private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

public static int copy(InputStream input, OutputStream output) throws IOException {
  long count = copyLarge(input, output);
  if (count > Integer.MAX_VALUE) {
    return -1;
  }
  return (int) count;
}

public static long copyLarge(InputStream input, OutputStream output)
    throws IOException {
   byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
   long count = 0;
   int n = 0;
   while (-1 != (n = input.read(buffer))) {
     output.write(buffer, 0, n);
     count += n;
   }
   return count;
}

put those 2 methods in one of your helper classes and you're good to go.

Mihai Toader
  • 12,041
  • 1
  • 29
  • 33
  • 1
    won't this be more effective if the NIO was used? – IAdapter Jan 10 '11 at 10:12
  • 1
    i had mixed results with nio :). It might be better or it might not. The code is definitely a little more complex and you really need to test the results on your machine to make sure is good enough. Look here for some code: http://thomaswabner.wordpress.com/2007/10/09/fast-stream-copy-using-javanio-channels/ – Mihai Toader Jan 10 '11 at 10:13
  • 1
    +1 ymmv, but i've had a hard time making the nio version faster than good old streams – Adam Rabung Dec 04 '11 at 14:47