在java中将inputstream转换为字节数组

wtlkbnrh  于 2021-09-13  发布在  Java
关注(0)|答案(30)|浏览(474)

我如何阅读整本书 InputStream 进入字节数组?

ca1c2owp

ca1c2owp1#

您可以将cactoos库用于提供可重用的面向对象java组件。这个库强调oop,所以没有静态方法、null等,只有真实对象及其契约(接口)。像读取inputstream这样的简单操作可以这样执行

final InputStream input = ...;
final Bytes bytes = new BytesOf(input);
final byte[] array = bytes.asBytes();
Assert.assertArrayEquals(
    array,
    new byte[]{65, 66, 67}
);

有专用类型的 Bytes 用于处理数据结构 byte[] 使我们能够使用面向对象的策略来解决手头的任务。程序性“实用”方法禁止我们做的事情。例如,您需要加密从该文件读取的字节 InputStream 到base64。在本例中,您将在base64的实现中使用decorator模式和wrap bytes对象。cactoos已经提供了这样的实现:

final Bytes encoded = new BytesBase64(
    new BytesOf(
        new InputStreamOf("XYZ")
    )
);
Assert.assertEquals(new TextOf(encoded).asString(), "WFla");

您可以使用装饰器模式以相同的方式解码它们

final Bytes decoded = new Base64Bytes(
    new BytesBase64(
        new BytesOf(
            new InputStreamOf("XYZ")
        )
    )
);
Assert.assertEquals(new TextOf(decoded).asString(), "XYZ");

无论您的任务是什么,您都将能够创建自己的实现 Bytes 解决它。

mrphzbgm

mrphzbgm2#

kotlin中的解决方案(当然也可以在java中使用),它包括两种情况,即您是否知道大小:

fun InputStream.readBytesWithSize(size: Long): ByteArray? {
        return when {
            size < 0L -> this.readBytes()
            size == 0L -> ByteArray(0)
            size > Int.MAX_VALUE -> null
            else -> {
                val sizeInt = size.toInt()
                val result = ByteArray(sizeInt)
                readBytesIntoByteArray(result, sizeInt)
                result
            }
        }
    }

    fun InputStream.readBytesIntoByteArray(byteArray: ByteArray,bytesToRead:Int=byteArray.size) {
        var offset = 0
        while (true) {
            val read = this.read(byteArray, offset, bytesToRead - offset)
            if (read == -1)
                break
            offset += read
            if (offset >= bytesToRead)
                break
        }
    }

如果您知道大小,那么与其他解决方案相比,它可以节省两倍的内存使用量(在很短的时间内,但仍然可能有用)。这是因为您必须将整个流读取到底,然后将其转换为字节数组(类似于将arraylist转换为数组)。
因此,例如,如果您在android上,并且需要处理一些uri,您可以尝试使用以下方法获取大小:

fun getStreamLengthFromUri(context: Context, uri: Uri): Long {
        context.contentResolver.query(uri, arrayOf(MediaStore.MediaColumns.SIZE), null, null, null)?.use {
            if (!it.moveToNext())
                return@use
            val fileSize = it.getLong(it.getColumnIndex(MediaStore.MediaColumns.SIZE))
            if (fileSize > 0)
                return fileSize
        }
        //if you wish, you can also get the file-path from the uri here, and then try to get its size, using this: https://stackoverflow.com/a/61835665/878126
        FileUtilEx.getFilePathFromUri(context, uri, false)?.use {
            val file = it.file
            val fileSize = file.length()
            if (fileSize > 0)
                return fileSize
        }
        context.contentResolver.openInputStream(uri)?.use { inputStream ->
            if (inputStream is FileInputStream)
                return inputStream.channel.size()
            else {
                var bytesCount = 0L
                while (true) {
                    val available = inputStream.available()
                    if (available == 0)
                        break
                    val skip = inputStream.skip(available.toLong())
                    if (skip < 0)
                        break
                    bytesCount += skip
                }
                if (bytesCount > 0L)
                    return bytesCount
            }
        }
        return -1L
    }
kuhbmx9i

kuhbmx9i3#

以下是一个优化版本,它尝试尽可能避免复制数据字节:

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;
   }
}
ltskdhd1

ltskdhd14#

您可以尝试cactoos:

byte[] array = new BytesOf(stream).bytes();
3j86kqsm

3j86kqsm5#

java 7及更高版本:

import sun.misc.IOUtils;
...
InputStream in = ...;
byte[] buf = IOUtils.readFully(in, -1, false);
o3imoua4

o3imoua46#

这是我的复制粘贴版本:

@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();
}
blmhpbnm

blmhpbnm7#

我用这个。

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();
        }
    }
nhjlsmyf

nhjlsmyf8#

您可以使用ApacheCommonsIO来处理此任务和类似的任务。
这个 IOUtils 类型有一个静态方法来读取 InputStream 并返回一个 byte[] .

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

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

gk7wooem

gk7wooem9#

您需要从数据库中读取每个字节 InputStream 然后写给一个 ByteArrayOutputStream .
然后,您可以通过调用 toByteArray() :

InputStream is = ...
ByteArrayOutputStream buffer = new ByteArrayOutputStream();

int nRead;
byte[] data = new byte[16384];

while ((nRead = is.read(data, 0, data.length)) != -1) {
  buffer.write(data, 0, nRead);
}

return buffer.toByteArray();
fkvaft9z

fkvaft9z10#

最后,二十年后,由于java 9,有了一个不需要第三方库的简单解决方案:

InputStream is;
…
byte[] array = is.readAllBytes();

还要注意方便的方法 readNBytes(byte[] b, int off, int len)transferTo(OutputStream) 解决经常性需要。

xe55xuns

xe55xuns11#

使用香草java的 DataInputStream 及其 readFully 方法(至少从java 1.4开始存在):

...
byte[] bytes = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(bytes);
...

这个方法还有其他一些风格,但我一直在这个用例中使用它。

agxfikkp

agxfikkp12#

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

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

6mzjoqzu13#

一如既往,spring框架(自3.2.2以来的spring核心)也为您提供了一些东西: StreamUtils.copyToByteArray()

7lrncoxx

7lrncoxx14#

public static byte[] getBytesFromInputStream(InputStream is) throws IOException {
    ByteArrayOutputStream os = new ByteArrayOutputStream(); 
    byte[] buffer = new byte[0xFFFF];
    for (int len = is.read(buffer); len != -1; len = is.read(buffer)) { 
        os.write(buffer, 0, len);
    }
    return os.toByteArray();
}
5tmbdcev

5tmbdcev15#

安全解决方案(具有 close 流(正确):
java 9+:

final byte[] bytes;
 try (inputStream) {
     bytes = inputStream.readAllBytes();
 }

java 8:

public static byte[] readAllBytes(InputStream inputStream) throws IOException {
     final int bufLen = 4 * 0x400; // 4KB
     byte[] buf = new byte[bufLen];
     int readLen;
     IOException exception = null;

     try {
         try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
             while ((readLen = inputStream.read(buf, 0, bufLen)) != -1)
                 outputStream.write(buf, 0, readLen);

             return outputStream.toByteArray();
         }
     } catch (IOException e) {
         exception = e;
         throw e;
     } finally {
         if (exception == null) inputStream.close();
         else try {
             inputStream.close();
         } catch (IOException e) {
             exception.addSuppressed(e);
         }
     }
 }

kotlin(当无法访问java 9+时):

@Throws(IOException::class)
 fun InputStream.readAllBytes(): ByteArray {
     val bufLen = 4 * 0x400 // 4KB
     val buf = ByteArray(bufLen)
     var readLen: Int = 0

     ByteArrayOutputStream().use { o ->
         this.use { i ->
             while (i.read(buf, 0, bufLen).also { readLen = it } != -1)
                 o.write(buf, 0, readLen)
         }

         return o.toByteArray()
     }
 }

避免嵌套 use 看这里。
scala(当java 9+不可访问时)(作者@joan。thx):

def readAllBytes(inputStream: InputStream): Array[Byte] =
  Stream.continually(inputStream.read).takeWhile(_ != -1).map(_.toByte).toArray

相关问题