java.io包中的 ByteArrayInputStream 类可用于读取输入数组(字节)。
要创建字节数组输入流,我们必须首先导入java.io.ByteArrayInputStream包。导入包后,我们有两个构造函数可用于创建输入流:
ByteArrayInputStream input = new ByteArrayInputStream(arr);
ByteArrayInputStream input = new ByteArrayInputStream(arr, 2, 2);
类里面有4个字段:
// Byte array provided by the creator of the stream
protected byte buf[];
// Index of the next character to read from the input stream's buffer
protected int pos;
// Current marked position in the stream
protected int mark = 0;
// Index is one greater than the last valid character in the input stream's buffer
protected int count;
这是我们的构造函数:
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
public ByteArrayInputStream(byte buf[], int offset, int length) {
this.buf = buf;
this.pos = offset;
this.count = Math.min(offset + length, buf.length);
this.mark = offset;
}
ByteArrayInputStream 类的方法
方法 | 行动 |
---|---|
内部读取() | 从此输入流中读取下一个字节的数据。 |
int read(byte b[], int off, int len) | 从输入流中读取几个字节并将它们存储在缓冲区数组b中。 off是目标数组b的偏移量。 len是要读取的最大字节数。 |
长跳过(长n) | 跳过此输入流中的 n 个字节的输入。返回跳过的字节数(如果我们到达输入流的末尾,它可能小于 n)。 |
内部可用() | 返回可以从此输入流中读取(或跳过)的剩余字节数。 |
无效重置() | 将缓冲区重置为标记位置。标记的位置为 0,除非标记了另一个位置或在构造函数中指定了不同的偏移量。 |
布尔标记支持() | 检查此InputStream是否支持标记/重置。为ByteArrayInputStream返回true。 |
无效关闭() | 什么都不做。 |
无效标记(int readAheadLimit) | 设置标记等于当前位置的字段。如果调用了reset方法,那么后续的读取将从该位置开始。readAheadLimit参数未使用且不影响该方法的行为。 |
让我们仔细看看这些方法,看看它们在实践中是如何工作的。
读()
当您想像从普通InputStream读取字节一样从ByteArrayInputStream读取字节时,可以使用read()方法。
public static void main(String[] args) {
byte[] array = {1, 2, 3, 4};
try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
for (int i = 0; i < array.length; i++) {
int data = input.read();
System.out.print(data + ", ");
}
} catch (IOException e) {
e.printStackTrace();
}
}
可用的()
如果你想检查你的缓冲区中是否有东西,你可以调用available()方法。
public static void main(String[] args) {
byte[] array = {1, 2, 3, 4};
try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
System.out.println("Bytes available for reading: " + input.available());
input.read();
System.out.println("Bytes available for reading " + input.available());
input.read();
System.out.println("Bytes available for reading " + input.available());
} catch (IOException e) {
e.printStackTrace();
}
}
我们将看到每次从缓冲区读取后可用于读取的字节数都会发生变化。
输出:
可供读取的字节数:3
可供读取的字节数:2
跳过(长n)
您可以使用skip()方法跳过一定数量的字节而不读取它们。
public static void main(String[] args) {
byte[] array = {1, 2, 3, 4};
try (ByteArrayInputStream input = new ByteArrayInputStream(array)) {
input.skip(2);
while (input.available() != 0) {
int data = input.read();
System.out.print(data + ", ");
}
} catch (IOException e) {
e.printStackTrace();
}
}
输出:
重置()
此方法将缓冲流的位置重置为最后标记的位置。除非设置不同的标记,否则它是位置 0。
public static void main(String[] args) {
byte[] buf = {65, 66, 67, 68, 69};
try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
System.out.println("Calling reset() method");
input.reset();
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
} catch (IOException e) {
e.printStackTrace();
}
}
我们将看到调用reset()方法会将我们带到流的起点。
输出:
读取:66
读取:67
读取:68
调用 reset() 方法
读取:65
读取:66
标记(int readAheadLimit)
ByteArrayInputStream类的mark ()方法在当前字节位置设置内部标记,即紧接在先前读取的字节之后。此方法采用一个参数,该参数指示在标记之后流变为无效之前可以读取多少字节。默认情况下,如果未显式设置标记,则ByteArrayInputStream会标记位置 0 或传递给其构造函数的偏移量的位置。重要的是要注意readAheadLimit标记与此类无关。
/* Note: For this class, {@code readAheadLimit}
* has no meaning.
*
* @since 1.1
*/
public void mark(int readAheadLimit) {
mark = pos;
}
下面是使用mark()和reset()方法在ByteArrayInputStream中设置标记的示例。我们将在前面的示例中添加对mark()方法的调用:
public static void main(String[] args) {
byte[] buf = {65, 66, 67, 68, 69};
try (ByteArrayInputStream input = new ByteArrayInputStream(buf)) {
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
input.mark(5);
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
System.out.println("Calling reset() method");
input.reset();
System.out.println("Read: " + input.read());
System.out.println("Read: " + input.read());
} catch (IOException e) {
e.printStackTrace();
}
}
我们可以看到当前流的位置发生了变化。
输出:
读取:66
读取:67
读取:68
读取:69
调用 reset() 方法
读取:68
读取:69
标记支持()
markSupported ()方法让您检查是否可以设置标记。要了解返回值的来源,让我们转到方法的代码:
/**
* Tests if this {@code InputStream} supports mark/reset. The
* {@code markSupported} method of {@code ByteArrayInputStream}
* always returns {@code true}.
*
* @since 1.1
*/
public boolean markSupported() {
return true;
}
该方法始终返回true。让我们在实践中对此进行测试。
public static void main(String[] args) {
byte[] buf = {65, 66, 67, 68, 69};
try (ByteArrayInputStream bais = new ByteArrayInputStream(buf)) {
boolean isMarkSupported = bais.markSupported();
System.out.println("isMarkSupported: " + isMarkSupported);
System.out.println("Read: " + bais.read());
System.out.println("Read: " + bais.read());
bais.mark(1);
System.out.println("Read: " + bais.read());
isMarkSupported = bais.markSupported();
System.out.println("isMarkSupported: " + isMarkSupported);
bais.reset();
isMarkSupported = bais.markSupported();
System.out.println("isMarkSupported: " + isMarkSupported);
} catch (IOException e) {
e.printStackTrace();
}
}
在执行了mark()和reset()方法之后,我们的流就准备好了并且支持标记:
输出:
读取:65
读取:66
读取:67
isMarkSupported:true
isMarkSupported:true
关闭()
为了理解close方法,让我们也看一下它的内部:
/**
* Closing a {@code ByteArrayInputStream} has no effect. The methods in
* this class can be called after the stream has been closed without
* generating an {@code IOException}.
*/
public void close() throws IOException {
}
close 方法的文档告诉我们关闭 ByteArrayInputStream没有任何效果。可以在流关闭后调用ByteArrayInputStream类方法而不抛出IOException。
我们能得出什么结论?
当我们想从字节数组中读取数据时,我们需要一个ByteArrayInputStream 。将此类与知道如何使用InputStreams的其他代码结合使用而不是单独使用此类通常是有意义的。
GO TO FULL VERSION