如何将整个输入流读到字节数组?


当前回答

这是我的复制粘贴版本:

@SuppressWarnings("empty-statement")
public static byte[] inputStreamToByte(InputStream is) throws IOException {
    if (is == null) {
        return null;
    }
    // Define a size if you have an idea of it.
    ByteArrayOutputStream r = new ByteArrayOutputStream(2048);
    byte[] read = new byte[512]; // Your buffer size.
    for (int i; -1 != (i = is.read(read)); r.write(read, 0, i));
    is.close();
    return r.toByteArray();
}

其他回答

如果你碰巧使用谷歌Guava,它将像使用ByteStreams一样简单:

byte[] bytes = ByteStreams.toByteArray(inputStream);

下面是一个优化的版本,尽量避免复制数据字节:

private static byte[] loadStream (InputStream stream) throws IOException {
   int available = stream.available();
   int expectedSize = available > 0 ? available : -1;
   return loadStream(stream, expectedSize);
}

private static byte[] loadStream (InputStream stream, int expectedSize) throws IOException {
   int basicBufferSize = 0x4000;
   int initialBufferSize = (expectedSize >= 0) ? expectedSize : basicBufferSize;
   byte[] buf = new byte[initialBufferSize];
   int pos = 0;
   while (true) {
      if (pos == buf.length) {
         int readAhead = -1;
         if (pos == expectedSize) {
            readAhead = stream.read();       // test whether EOF is at expectedSize
            if (readAhead == -1) {
               return buf;
            }
         }
         int newBufferSize = Math.max(2 * buf.length, basicBufferSize);
         buf = Arrays.copyOf(buf, newBufferSize);
         if (readAhead != -1) {
            buf[pos++] = (byte)readAhead;
         }
      }
      int len = stream.read(buf, pos, buf.length - pos);
      if (len < 0) {
         return Arrays.copyOf(buf, pos);
      }
      pos += len;
   }
}

您可以使用Apache Commons IO来处理这个任务和类似的任务。

IOUtils类型有一个静态方法来读取InputStream并返回一个字节[]。

InputStream is;
byte[] bytes = IOUtils.toByteArray(is);

这将在内部创建一个ByteArrayOutputStream并将字节复制到输出,然后调用toByteArray()。它通过以4KiB为块复制字节来处理大文件。

我用这个。

public static byte[] toByteArray(InputStream is) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        try {
            byte[] b = new byte[4096];
            int n = 0;
            while ((n = is.read(b)) != -1) {
                output.write(b, 0, n);
            }
            return output.toByteArray();
        } finally {
            output.close();
        }
    }

如果你使用ByteArrayOutputStream,你会做一个额外的拷贝。如果你在开始读取流之前知道它的长度(例如,InputStream实际上是FileInputStream,你可以在文件上调用file.length(),或者InputStream是一个zipfile条目InputStream,你可以调用zipEntry.length()),那么直接写入byte[]数组会更好——它使用一半的内存,并节省时间。

// Read the file contents into a byte[] array
byte[] buf = new byte[inputStreamLength];
int bytesRead = Math.max(0, inputStream.read(buf));

// If needed: for safety, truncate the array if the file may somehow get
// truncated during the read operation
byte[] contents = bytesRead == inputStreamLength ? buf
                  : Arrays.copyOf(buf, bytesRead);

注意:上面的最后一行处理的是在读取流时被截断的文件,如果你需要处理这种可能性,但是如果在读取流时文件变长了,byte[]数组中的内容将不会被延长以包括新的文件内容,数组将简单地被截断为旧的长度inputStreamLength。