1. Overview
1.概述
In this quick tutorial, we’re going to take a look at how to convert an InputStream to a byte[] and ByteBuffer – first using plain Java, then using Guava and Commons IO.
在这个快速教程中,我们将看看如何将InputStream转换为byte[] 和ByteBuffer – 首先使用普通Java,然后使用Guava和Commons IO。
This article is part of the “Java – Back to Basic” series here on Baeldung.
本文是Baeldung网站上“Java – Back to Basic “系列的一部分。
2. Convert to Byte Array
2.转换为字节数组
Let’s look at obtaining a byte array from simple input streams. The important aspect of a byte array is that it enables an indexed (fast) access to each 8-bit (a byte) value stored in memory. Hence, you can manipulate these bytes to control each bit. We are going to take a look at how to convert a simple input stream to a byte[] – first using plain Java, then using Guava and Apache Commons IO.
让我们来看看如何从简单的输入流中获得一个字节数组。字节数组的重要意义在于它能够对存储在内存中的每个8位(一个字节)值进行索引(快速)访问。因此,你可以操作这些字节来控制每个比特。我们将看看如何将一个简单的输入流转换为byte[] – 首先使用普通Java,然后使用Guava和Apache Commons I/a>。
2.1. Convert Using Plain Java
2.1.使用普通Java进行转换
Let’s start with a Java solution focused on dealing with a fixed size stream:
让我们从一个专注于处理固定大小流的Java解决方案开始。
@Test
public void givenUsingPlainJavaOnFixedSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
byte[] targetArray = new byte[is.available()];
is.read(targetArray);
}
In the case of a buffered stream – where we’re dealing with a buffered stream and don’t know the exact size of the underlying data, we need to make the implementation more flexible:
在缓冲流的情况下–我们处理的是一个缓冲流,不知道底层数据的确切大小,我们需要使实现更加灵活。
@Test
public void givenUsingPlainJavaOnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 }); // not really known
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[4];
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] targetArray = buffer.toByteArray();
}
Starting with Java 9, we can achieve the same with a dedicated readNbytes method:
从Java 9开始,我们可以通过一个专门的readNbytes方法实现同样的目的。
@Test
public void givenUsingPlainJava9OnUnknownSizeStream_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2, 3, 4, 5, 6 });
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[4];
while ((nRead = is.readNBytes(data, 0, data.length)) != 0) {
System.out.println("here " + nRead);
buffer.write(data, 0, nRead);
}
buffer.flush();
byte[] targetArray = buffer.toByteArray();
}
The difference between these two methods is very subtle.
这两种方法之间的区别非常微妙。
The first one, read(byte[] b, int off, int len), reads up to len bytes of data from the input stream, whereas the second one, readNBytes(byte[] b, int off, int len), reads exactly the requested number of bytes.
第一个,read(byte[] b, int off, int len),从输入流中最多读取len字节的数据,而第二个,readNBytes(byte[] b, int off, int len),正好读取要求的字节数量。
Additionally, read returns -1 if there’s no more data available in the input stream. readNbytes, however, always returns the actual number of bytes read into the buffer.
此外,read如果输入流中没有更多的数据,则返回-1。然而,readNbytes,总是返回读入缓冲区的实际字节数。
We can also read all the bytes at once:
我们也可以一次性读取所有的字节。
@Test
public void
givenUsingPlainJava9_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
InputStream is = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
byte[] data = is.readAllBytes();
}
2.2. Convert Using Guava
2.2.使用Guava进行转换
Let’s now look at the simple Guava based solution – using the convenient ByteStreams utility class:
现在让我们来看看基于Guava的简单解决方案–使用方便的ByteStreams实用类。
@Test
public void givenUsingGuava_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
InputStream initialStream = ByteSource.wrap(new byte[] { 0, 1, 2 }).openStream();
byte[] targetArray = ByteStreams.toByteArray(initialStream);
}
2.3. Convert Using Commons IO
2.3.使用Commons IO进行转换
And finally – a straightforward solution using Apache Commons IO:
最后–一个使用Apache Commons IO的直接解决方案。
@Test
public void givenUsingCommonsIO_whenConvertingAnInputStreamToAByteArray_thenCorrect()
throws IOException {
ByteArrayInputStream initialStream = new ByteArrayInputStream(new byte[] { 0, 1, 2 });
byte[] targetArray = IOUtils.toByteArray(initialStream);
}
The method IOUtils.toByteArray() buffers the input internally, so there is no need to use a BufferedInputStream instance when buffering is needed.
方法IOUtils.toByteArray()在内部对输入进行缓冲,因此在需要缓冲时,不需要使用BufferedInputStream实例。
3. Convert to ByteBuffer
3.转换为ByteBuffer
Now, let’s look at obtaining a ByteBuffer from an InputStream. This is useful whenever we need to do fast and direct low-level I/O operations in memory.
现在,让我们看看如何从InputStream中获取ByteBuffer。这在我们需要在内存中进行快速和直接的低级I/O操作时是有用的。
Using the same approach as the above sections, we’re going to take a look at how to convert an InputStream to a ByteBuffer – first using plain Java, then using Guava and Commons IO.
使用与上述章节相同的方法,我们将看看如何将InputStream转换为ByteBuffer – 首先使用普通Java,然后使用Guava和Commons IO。
3.1. Convert Using Plain Java
3.1.使用普通Java进行转换
In the case of a byte stream – we know the exact size of the underlying data. Let’s use the ByteArrayInputStream#available method to read the byte stream into a ByteBuffer:
在字节流的情况下,我们知道底层数据的确切大小。让我们使用ByteArrayInputStream#available方法,将字节流读入ByteBuffer。
@Test
public void givenUsingCoreClasses_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch()
throws IOException {
byte[] input = new byte[] { 0, 1, 2 };
InputStream initialStream = new ByteArrayInputStream(input);
ByteBuffer byteBuffer = ByteBuffer.allocate(3);
while (initialStream.available() > 0) {
byteBuffer.put((byte) initialStream.read());
}
assertEquals(byteBuffer.position(), input.length);
}
3.2. Convert Using Guava
3.2.使用Guava进行转换
Let’s now look at a simple Guava-based solution – using the convenient ByteStreams utility class:
现在让我们看看一个简单的基于Guava的解决方案–使用方便的ByteStreams实用类。
@Test
public void givenUsingGuava__whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch()
throws IOException {
InputStream initialStream = ByteSource
.wrap(new byte[] { 0, 1, 2 })
.openStream();
byte[] targetArray = ByteStreams.toByteArray(initialStream);
ByteBuffer bufferByte = ByteBuffer.wrap(targetArray);
while (bufferByte.hasRemaining()) {
bufferByte.get();
}
assertEquals(bufferByte.position(), targetArray.length);
}
Here we use a while loop with the method hasRemaining to show a different way to read all the bytes into the ByteBuffer. Otherwise, the assertion would fail because the ByteBuffer index position will be zero.
在这里,我们使用了一个带有hasRemaining方法的while循环,以展示一种不同的方式将所有字节读入ByteBuffer。否则,断言将会失败,因为ByteBuffer索引位置将为零。
3.3. Convert Using Commons IO
3.3.使用Commons IO进行转换
And finally – using Apache Commons IO and the IOUtils class:
最后–使用Apache Commons IO和IOUtils类。
@Test
public void givenUsingCommonsIo_whenByteArrayInputStreamToAByteBuffer_thenLengthMustMatch()
throws IOException {
byte[] input = new byte[] { 0, 1, 2 };
InputStream initialStream = new ByteArrayInputStream(input);
ByteBuffer byteBuffer = ByteBuffer.allocate(3);
ReadableByteChannel channel = newChannel(initialStream);
IOUtils.readFully(channel, byteBuffer);
assertEquals(byteBuffer.position(), input.length);
}
4. Conclusion
4.总结
This article illustrated various ways to convert a raw input stream to a byte array and a ByteBuffer using plain Java, Guava, and Apache Commons IO.
本文说明了使用普通Java、Guava和Apache Commons IO将原始输入流转换为字节数组和ByteBuffer的各种方法。
The implementation of all these examples can be found in our GitHub project.
所有这些例子的实现都可以在我们的GitHub项目中找到。