您的位置:首页 > 编程语言 > Java开发

Java IO - ByteArrayInputStream&ByteArrayOutputStream

2016-05-22 17:31 841 查看

基本概念

ByteArrayInputStream:字节数组输入流,继承自 InputStream。它会在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区中。

ByteArrayOutputStream:字节数组输出流,继承自OutputStream是与 ByteArrayInputStream 相对应的输出流。

实例探究

1.ByteArrayInputStream

下面来看一个完整的实例。

public class Test {

// 英文字母
private static final byte[] ArrayLetters = {
0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
0x76, 0x77, 0x78, 0x79,0x7A };

private static final int LEN = 5;

public static void main(String[] args) throws IOException {
read();
}

private static void read() {

ByteArrayInputStream bis = new ByteArrayInputStream(ArrayLetters);

// 逐个读取字节,输出 a,b,c,d,e
for (int i = 0; i < LEN; i++) {
if (bis.available() != -1) {
int count = bis.read();
System.out.print((char) count);
}
}
System.out.println();

// 判断是否支持标记操作
if (!bis.markSupported()) {
return;
}

// 标记当前字节,即 f(与 reset 配套使用)
bis.mark(0);

// 跳过5个字节,跳过 f,g,h,i,j
bis.skip(5);

//按照字节数组读取,输出结果 k,l,m,n,o
byte[] buf = new byte[LEN];
bis.read(buf, 0, LEN);
System.out.print(new String(buf));
System.out.println();

// 重置字节流,回到 mark 的位置,重新读取字符数组,输出 f,g,h,i,j
bis.reset();
bis.read(buf, 0, LEN);
System.out.print(new String(buf));
}


2.ByteArrayOutputStream

public static void main(String[] args) throws IOException {
write();
}

private static void write() throws IOException {

ByteArrayOutputStream bos = new ByteArrayOutputStream(ArrayLetters.length);

// 按字节写入,输出 a
bos.write(0x61);
System.out.println(bos.toString());

// 按字节数组写入,输出 a,b,c,d
bos.write(ArrayLetters, 1, 3);
System.out.println(bos.toString());

// 缓冲数组中的字节数量,输出 4
int size = bos.size();
System.out.println(size);

// 转换成字节数组,输出 a,b,c,d
byte[] buf = bos.toByteArray();
System.out.println(new String(bos.toByteArray()));

//将内容输出到其他流
bos.writeTo(new ByteArrayOutputStream(size));

}


源码分析

1.ByteArrayInputStream

首先来看它的类结构,如下图所示。



通过类结构图,我们知道它定义了4个成员变量。

//缓冲数组
protected byte buf[];

//索引位置,表示当前读取的位置
protected int pos;

//标记位,标记当前读取的位置
protected int mark = 0;

//要读取的字节数组的长度
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;
}


接下来着重来看它的 read 方法。

//按字节读取
public synchronized int read() {

//判断索引位置,并取出数组上相应位置的值。读取完毕返回 -1。
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}

//按字节数组读取
public synchronized int read(byte b[], int off, int len) {

if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}

//判断缓冲数组的字节是否已经全部读取
if (pos >= count) {
return -1;
}

//判断要读取的字节数量是否超出了缓冲数组中剩余的字节数量
if (pos + len > count) {
len = count - pos;
}

if (len <= 0) {
return 0;
}

//重点-->将缓冲数组上的字节(从索引位置开始)复制到当前数组中
System.arraycopy(buf, pos, b, off, len);

pos += len;

return len;
}


最后再来看看类中剩余的几个方法。

//表示要跳过的字节,通过改变数组的索引位置实现
public synchronized long skip(long n) {
if (pos + n > count) {
n = count - pos;
}
if (n < 0) {
return 0;
}
pos += n;
return n;
}

//返回缓冲数组中剩余可读取的字节数量
public synchronized int available() {
return count - pos;
}

//表示字节数入流默认支持标记
public boolean markSupported() {
return true;
}

//标记字节
public void mark(int readAheadLimit) {
mark = pos;
}

//释放标记的字节
public synchronized void reset() {
pos = mark;
}

//关闭流,是个空方法,说明缓冲数组输入流不需要关闭流操作
public void close() throws IOException {
}


2.ByteArrayOutputStream

首先来看它的类结构,如下图所示。



通过类结构图,我们知道它定义了2个成员变量,意义与 ByteArrayInputStream 中的成员变量一样,这里不再阐述。接下来看它的构造方法。

public ByteArrayOutputStream() {
this(32);
}

public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: " + size);
}
buf = new byte[size];
}


观察代码发现 ByteArrayOutputStream 的操作跟 ByteArrayInputStream 一样,也是通过缓冲数组完成。如果不指定缓冲数组的大小,默认为32。再来着重看看它的 write 方法。

//按字节写入
public synchronized void write(int b) {

int newcount = count + 1;

//判断下一次写入时长度如果超出缓冲数组的容量,则创建新的缓冲数组并将内容复制进入
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}

//关键-->写入操作
buf[count] = (byte) b;

count = newcount;
}

//按字节数组写入
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}

int newcount = count + len;

if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}

//关键-->写入操作
System.arraycopy(b, off, buf, count, len);

count = newcount;
}


最后再来看看它的其他方法。

//重点 -->将内容输出到其他流
public synchronized void writeTo(OutputStream out) throws IOException {
out.write(buf, 0, count);
}

public synchronized void reset() {
count = 0;
}

//转化成字节数组
public synchronized byte toByteArray()[] {
return Arrays.copyOf(buf, count);
}

public synchronized int size() {
return count;
}

public synchronized String toString() {
return new String(buf, 0, count);
}

public synchronized String toString(String charsetName) throws UnsupportedEncodingException {
return new String(buf, 0, count, charsetName);
}

public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, count);
}

//同字节数组输入流一样,不用关闭流
public void close() throws IOException {
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java-IO