将InputStream写入HttpServletResponse

Sab*_*lly 19 java servlets inputstream outputstream java-ee

我有一个我想要写入HttpServletResponse的InputStream.这种方法由于使用byte []而花费的时间太长

InputStream is = getInputStream();
int contentLength = getContentLength();

byte[] data = new byte[contentLength];
is.read(data);

//response here is the HttpServletResponse object
response.setContentLength(contentLength);
response.write(data);
Run Code Online (Sandbox Code Playgroud)

在速度和效率方面,我想知道什么是最好的方法.

Bal*_*usC 45

只需写入块而不是先将其完全复制到Java的内存中.以下基本示例将其写入10KB的块中.这样,您最终只能获得10KB的内存使用量,而不是完整的内容长度.此外,最终用户将更快地开始获取部分内容.

response.setContentLength(getContentLength());
byte[] buffer = new byte[10240];

try (
    InputStream input = getInputStream();
    OutputStream output = response.getOutputStream();
) {
    for (int length = 0; (length = input.read(buffer)) > 0;) {
        output.write(buffer, 0, length);
    }
}
Run Code Online (Sandbox Code Playgroud)

作为creme de la creme的性能,您可以使用NIO Channels和直接分配ByteBuffer.在某个自定义实用程序类中创建以下实用程序/帮助程序方法,例如Utils:

public static long stream(InputStream input, OutputStream output) throws IOException {
    try (
        ReadableByteChannel inputChannel = Channels.newChannel(input);
        WritableByteChannel outputChannel = Channels.newChannel(output);
    ) {
        ByteBuffer buffer = ByteBuffer.allocateDirect(10240);
        long size = 0;

        while (inputChannel.read(buffer) != -1) {
            buffer.flip();
            size += outputChannel.write(buffer);
            buffer.clear();
        }

        return size;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你使用如下:

response.setContentLength(getContentLength());
Utils.stream(getInputStream(), response.getOutputStream());
Run Code Online (Sandbox Code Playgroud)

  • 当然很多实用程序包已经定义了这个方法,所以一旦你开始使用Guava ... http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/io/ByteStreams.html# copy(java.io.InputStream,java.io.OutputStream) (2认同)