关于java:将InputStream转换为byte []的最有效方法?

Most efficient way to convert InputStream into byte[]?

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
ArrayList<Byte> arrayList = new ArrayList<Byte>();
try {
    while (responseStream.available() > 0) {
        arrayList.add(responseStream.readByte());
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
Iterator<Byte> iterator = arrayList.iterator();
byte[] bytes = new byte[arrayList.size()];
int i = 0;
while (iterator.hasNext()) {
    bytes[i++] = iterator.next();
}

在我的Web应用程序的每个页面加载中都会调用此代码。它似乎跑得很快,但有什么能让它跑得更快的吗?

编辑-使用字节数组输出流更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
    int read = responseStream.read();
    while (read != -1) {
        byteArrayOutputStream.write(read);
        read = responseStream.read();
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
byte[] bytes = byteArrayOutputStream.toByteArray();
return ok(bytes).as(response.getHeader("Content-type"));

编辑-基准测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
long t1 = System.nanoTime();

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
    int read = responseStream.read();
    while (read != -1) {
        byteArrayOutputStream.write(read);
        read = responseStream.read();
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
byte[] bytes = byteArrayOutputStream.toByteArray();

long t2 = System.nanoTime();
System.out.println(t2-t1);
return ok(bytes).as(response.getHeader("Content-type"));

100+请求后的平均时间-46873

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ChannelBufferInputStream responseStream = (ChannelBufferInputStream) response.getBodyAsStream();
long t1 = System.nanoTime();

ArrayList<Byte> arrayList = new ArrayList<Byte>();
try {
    while (responseStream.available() > 0) {
        arrayList.add(responseStream.readByte());
    }
} catch (IOException e) {
    e.printStackTrace();
    return internalServerError();
}
Iterator<Byte> iterator = arrayList.iterator();
byte[] bytes = new byte[arrayList.size()];
int i = 0;
while (iterator.hasNext()) {
    bytes[i++] = iterator.next();
}

long t2 = System.nanoTime();
System.out.println(t2-t1);
return ok(bytes).as(response.getHeader("Content-type"));

100+请求后的平均时间-522848

1
2
3
4
5
6
7
8
9
10
long t1 = System.nanoTime();
byte[] bytes;
try {
    bytes = org.apache.commons.io.IOUtils.toByteArray(responseStream);
} catch (Exception e) {
    return internalServerError();
}

long t2 = System.nanoTime();
System.out.println(t2-t1);

100+请求后的平均时间-45088

1
2
3
4
5
6
7
8
9
10
long t1 = System.nanoTime();
byte[] bytes;
try {
    bytes = sun.misc.IOUtils.readFully(responseStream, -1, true);
} catch (Exception e) {
    return internalServerError();
}

long t2 = System.nanoTime();
System.out.println(t2 - t1);

100+请求后的平均时间-20180


对。使用ByteArrayOutputStream而不是arraylist。然后从输入流中读取字节块(不使用available(),这几乎永远不应该使用),并将这些块写入bytearrayoutputstream,直到read()方法返回-1。然后在您的ByteArrayOutputStream上调用tobytearray()。

您可以使用guava的ByteStreams.toByteArray()方法,它可以为您完成所有这些工作,或者您可以阅读它的源代码,更好地了解它是如何完成的。阅读IO教程也会有所帮助。


apache commons io ioutils.tobytearray方法有什么问题?为了达到这个目的,我们已经优化了很多年。


为什么?除了对整个数据执行两个额外的复制步骤外,此代码完全等同于read(byte[])。你不需要这些。一个简单的read(byte[])的速度是它的几倍。

使用available()也是无效的。您需要完整的响应,而不仅仅是可以在不阻塞的情况下读取的部分。你需要循环。