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


当前回答

请参阅InputStream.available()文档:

It is particularly important to realize that you must not use this method to size a container and assume that you can read the entirety of the stream without needing to resize the container. Such callers should probably write everything they read to a ByteArrayOutputStream and convert that to a byte array. Alternatively, if you're reading from a file, File.length returns the current length of the file (though assuming the file's length can't change may be incorrect, reading a file is inherently racy).

其他回答

请参阅InputStream.available()文档:

It is particularly important to realize that you must not use this method to size a container and assume that you can read the entirety of the stream without needing to resize the container. Such callers should probably write everything they read to a ByteArrayOutputStream and convert that to a byte array. Alternatively, if you're reading from a file, File.length returns the current length of the file (though assuming the file's length can't change may be incorrect, reading a file is inherently racy).

如果您不想使用Apache common -io库,则此代码片段取自sun.misc.IOUtils类。它的速度几乎是使用ByteBuffers的普通实现的两倍:

public static byte[] readFully(InputStream is, int length, boolean readAll)
        throws IOException {
    byte[] output = {};
    if (length == -1) length = Integer.MAX_VALUE;
    int pos = 0;
    while (pos < length) {
        int bytesToRead;
        if (pos >= output.length) { // Only expand when there's no room
            bytesToRead = Math.min(length - pos, output.length + 1024);
            if (output.length < pos + bytesToRead) {
                output = Arrays.copyOf(output, pos + bytesToRead);
            }
        } else {
            bytesToRead = output.length - pos;
        }
        int cc = is.read(output, pos, bytesToRead);
        if (cc < 0) {
            if (readAll && length != Integer.MAX_VALUE) {
                throw new EOFException("Detect premature EOF");
            } else {
                if (output.length != pos) {
                    output = Arrays.copyOf(output, pos);
                }
                break;
            }
        }
        pos += cc;
    }
    return output;
}

如果你使用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。

您可以使用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[]使我们能够使用OOP策略来解决手头的任务。 一些程序性的“效用”方法将禁止我们做的事情。 例如,您需要将从此InputStream读取的字节封装到Base64。 在本例中,您将使用Decorator模式并在Base64的实现中封装Bytes对象。 Cactoos已经提供了这样的实现:

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

您可以使用Decorator模式以同样的方式解码它们

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

无论你的任务是什么,你都可以创建自己的Bytes实现来解决它。

你真的需要图像作为字节[]吗?你在字节[]中到底期望什么-图像文件的完整内容,以图像文件的任何格式编码,或RGB像素值?

这里的其他答案向您展示了如何将文件读入字节[]。您的字节[]将包含文件的确切内容,并且您需要对其进行解码才能对图像数据进行处理。

用于读取(和写入)图像的Java标准API是ImageIO API,您可以在javax.imageio包中找到它。你可以用一行代码从文件中读入一张图片:

BufferedImage image = ImageIO.read(new File("image.jpg"));

这将给您一个BufferedImage,而不是一个字节[]。要获取图像数据,可以在BufferedImage上调用getRaster()。这将为您提供一个光栅对象,该对象具有访问像素数据的方法(它有几个getPixel() / getPixels()方法)。

查找javax.imageio的API文档。ImageIO java.awt.image。BufferedImage, java。awt。image。raster等等。

ImageIO默认支持多种图像格式:JPEG, PNG, BMP, WBMP和GIF。可以添加对更多格式的支持(您需要一个实现ImageIO服务提供程序接口的插件)。

另请参阅下面的教程:使用图像