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


当前回答

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
    }

其他回答

ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (true) {
    int r = in.read(buffer);
    if (r == -1) break;
    out.write(buffer, 0, r);
}

byte[] ret = out.toByteArray();

这是我的复制粘贴版本:

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

安全解决方案(正确关闭流):

Java 9及更新版本: 最终字节[]字节; try (inputStream) { 字节= inputStream.readAllBytes(); }


Java 8 and older: 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::类) fun InputStream.readAllBytes(): ByteArray { val bufLen = 4 * 0x400 // 4KB val buf = ByteArray(bufLen) var readLen: Int = 0 ByteArrayOutputStream()。使用{o -> 这一点。使用{I -> i.read(buf, 0, bufLen)。{readLen = it} != -1) o.write(buf, 0, readLen) } 返回o.toByteArray () } } 避免嵌套使用请看这里。


Scala(当Java 9+不可访问时)(By @Joan。Thx): def readAllBytes(inputStream: inputStream): Array[Byte] = Stream.continually (read)。takeWhile(_ != -1).map(_. tobyte).toArray . take (_

Java 9最终会给你一个很好的方法:

InputStream in = ...;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
in.transferTo( bos );
byte[] bytes = bos.toByteArray();

另一种情况是在发送请求到服务器并等待响应后,通过流获得正确的字节数组。

/**
         * Begin setup TCP connection to PC app
         * to open integrate connection between mobile app and pc app (or mobile app)
         */
        mSocket = new Socket(IP, port);
       // mSocket.setSoTimeout(30000);

        DataOutputStream mDos = new DataOutputStream(mSocket.getOutputStream());

        String str = "MobileRequest#" + params[0] + "#<EOF>";

        mDos.write(str.getBytes());

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        /* Since data are accepted as byte, all of them will be collected in the
        following byte array which initialised with accepted data length. */
        DataInputStream mDis = new DataInputStream(mSocket.getInputStream());
        byte[] data = new byte[mDis.available()];

        // Collecting data into byte array
        for (int i = 0; i < data.length; i++)
            data[i] = mDis.readByte();

        // Converting collected data in byte array into String.
        String RESPONSE = new String(data);