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

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

我如何阅读整本书 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();
        }
    }
rqqzpn5f

rqqzpn5f8#

我知道为时已晚,但我认为这是一个更干净的解决方案,更具可读性。。。

/**
 * method converts {@link InputStream} Object into byte[] array.
 * 
 * @param stream the {@link InputStream} Object.
 * @return the byte[] array representation of received {@link InputStream} Object.
 * @throws IOException if an error occurs.
 */
public static byte[] streamToByteArray(InputStream stream) throws IOException {

    byte[] buffer = new byte[1024];
    ByteArrayOutputStream os = new ByteArrayOutputStream();

    int line = 0;
    // read bytes from stream, and store them in buffer
    while ((line = stream.read(buffer)) != -1) {
        // Writes bytes from byte array (buffer) into output stream.
        os.write(buffer, 0, line);
    }
    stream.close();
    os.flush();
    os.close();
    return os.toByteArray();
}
rggaifut

rggaifut9#

如果您使用bytearrayoutputstream,您正在进行额外的复制。如果在开始读取流之前知道流的长度(例如,inputstream实际上是一个fileinputstream,您可以对该文件调用file.length(),或者inputstream是一个zipfile条目inputstream,您可以调用ZipPentry.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);

n、 b.如果您需要处理这种可能性,则上面的最后一行处理在读取流时被截断的文件,但如果在读取流时文件变长,则byte[]数组中的内容将不会加长以包含新的文件内容,数组将被截断为原来的长度inputstreamlength。

carvr3hs

carvr3hs10#

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

/**
         * 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);
xmq68pz9

xmq68pz911#

在将s3对象转换为bytearray时,我们看到了一些aws事务的延迟。
注:s3对象是pdf文档(最大大小为3MB)。
我们使用选项#1(org.apache.commons.io.ioutils)将s3对象转换为bytearray。我们注意到s3提供了内置ioutils方法来将s3对象转换为bytearray,我们要求您确认将s3对象转换为bytearray的最佳方式是什么,以避免延迟。
选项1:

import org.apache.commons.io.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

选项2:

import com.amazonaws.util.IOUtils;
is = s3object.getObjectContent();
content =IOUtils.toByteArray(is);

另外,如果我们有其他更好的方法将s3对象转换为bytearray,请告诉我

8yoxcaq7

8yoxcaq712#

java 8路(感谢bufferedreader和adam bien)

private static byte[] readFully(InputStream input) throws IOException {
    try (BufferedReader buffer = new BufferedReader(new InputStreamReader(input))) {
        return buffer.lines().collect(Collectors.joining("\n")).getBytes(<charset_can_be_specified>);
    }
}

请注意,此解决方案会擦除回车符('\r'),可能不合适。

vfh0ocws

vfh0ocws13#

将它 Package 在datainputstream中,如果出于某种原因,它不在表中,只需使用read来敲打它,直到它给出-1或您要求的整个块。

public int readFully(InputStream in, byte[] data) throws IOException {
    int offset = 0;
    int bytesRead;
    boolean read = false;
    while ((bytesRead = in.read(data, offset, data.length - offset)) != -1) {
        read = true;
        offset += bytesRead;
        if (offset >= data.length) {
            break;
        }
    }
    return (read) ? offset : -1;
}
smtd7mpg

smtd7mpg14#

InputStream.available() 文档:
特别重要的是要认识到,您不能使用此方法来调整容器的大小,并假设您可以读取整个流,而无需调整容器的大小。此类调用者可能应该将读取的所有内容写入bytearrayoutputstream,并将其转换为字节数组。或者,如果您正在读取文件,file.length将返回文件的当前长度(尽管假设文件的长度不能更改可能是不正确的,但读取文件本身就是快速的)。

xghobddn

xghobddn15#

我试图编辑@numan的答案,并修复了写入垃圾数据的问题,但编辑被拒绝。虽然这段代码并不精彩,但我看不到其他更好的答案。以下是对我最有意义的:

ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buffer = new byte[1024]; // you can configure the buffer size
int length;

while ((length = in.read(buffer)) != -1) out.write(buffer, 0, length); //copy streams
in.close(); // call this in a finally block

byte[] result = out.toByteArray();

顺便说一句,bytearrayoutputstream无需关闭。try/finally结构因可读性而省略

相关问题