24

我有一个要写入 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);

我想知道在速度和效率方面什么可能是最好的方法。

4

3 回答 3

51

只需在块中写入,而不是先将其完全复制到 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);
    }
}

就性能而言,你可以使用 NIOChannels和直接分配的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;
    }
}

然后您使用如下:

response.setContentLength(getContentLength());
Utils.stream(getInputStream(), response.getOutputStream());
于 2012-04-13T14:21:58.510 回答
1
BufferedInputStream in = null;
BufferedOutputStream out = null;
OutputStream os;
os = new BufferedOutputStream(response.getOutputStream());
in = new BufferedInputStream(new FileInputStream(file));
out = new BufferedOutputStream(os);
byte[] buffer = new byte[1024 * 8];
int j = -1;
while ((j = in.read(buffer)) != -1) {
    out.write(buffer, 0, j);
}
于 2012-04-13T14:18:40.930 回答
0

我认为这非常接近最佳方式,但我建议进行以下更改。使用固定大小的缓冲区(比如 20K),然后在循环中进行读/写。

对于循环做类似的事情

byte[] buffer=new byte[20*1024];
outputStream=response.getOutputStream();
while(true) {
  int readSize=is.read(buffer);
  if(readSize==-1)
    break;
  outputStream.write(buffer,0,readSize);
}

ps:你的程序不会总是按原样工作,因为 read 并不总是填满你给它的整个数组。

于 2012-04-13T14:20:46.403 回答