Java InputStream to Byte Array and ByteBuffer – Java InputStream到字节数组和ByteBuffer

最后修改: 2014年 6月 21日

中文/混合/英文(键盘快捷键:t)

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,然后使用GuavaApache 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项目中找到。