[重学Java基础][Java IO流][Part.9] 字节数组输入输出流
- [重学Java基础][Java IO流][Part.9] 字节数组输入输出流
- ByteArrayInputStream
- 概述
- 源码分析
- 成员属性
- 成员方法
- 代码示例
- ByteArrayOutputStream
- 概述
- 源码分析
- 成员属性
- 成员方法
- 代码示例
ByteArrayInputStream
概述
ByteArrayInputStream字节数组输入流 继承与InputStream抽象类
和字符数组输入流类似 也是一个数据始终储存在内存中的节点流,也可称之为内存流
实际上并没有对外部数据源进行读入操作 直接采用内存中的数据
主要用于适配以字节输入流为参数的接口
源码分析
成员属性
字节数组 流的内容体
protected byte[] buf;
当前字节缓冲流 下一次读取的开始位置
protected int pos;
在缓冲流中的标记位置
protected int mark = 0;
字节数组缓冲流的长度
protected int count;
成员方法
构造方法
传入一个字节数组byte[] buf 为流的内容
public ByteArrayInputStream(byte[] buf) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
传入一个字节数组byte[] buf 并指定读入位置和长度 让读入部分为流的内容
public ByteArrayInputStream(byte[] buf, int offset, int length) {
this.buf = buf;
this.pos = offset;
取offset + length, buf.length中的小值 避免越界异常
this.count = Math.min(offset + length, buf.length);
标记位置默认为读入起始位置
this.mark = offset;
}
读入方法
读取下一个字节
public synchronized int read() {
判断下一个读入的索引是否超过数组大小
若没超过则返回下一个读入位置的字节
return this.pos < this.count ? this.buf[this.pos++] & 255 : -1;
}
读入字节数组byte[] b的数据并写入到流的字节内容体字节数组buf中
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) {
if (this.pos >= this.count) {
return -1;
} else {
int avail = this.count - this.pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
} else {
System.arraycopy(this.buf, this.pos, b, off, len);
this.pos += len;
return len;
}
}
} else {
throw new IndexOutOfBoundsException();
}
}
跳过与重置 各种流内都是大同小异的方法
public synchronized long skip(long n) {
long k = (long)(this.count - this.pos);
if (n < k) {
k = n < 0L ? 0L : n;
}
this.pos = (int)((long)this.pos + k);
return k;
}
public synchronized void reset() {
this.pos = this.mark;
}
还可以读取的字符大小
public synchronized int available() {
return this.count - this.pos;
}
是否支持标记
public boolean markSupported() {
return true;
}
标记
public void mark(int readAheadLimit) {
this.mark = this.pos;
}
关闭 类似 其他内存流 并无实际内容
public void close() throws IOException {
}
代码示例
示例1
ByteArrayInputStream bais=new ByteArrayInputStream(new byte[]{'a','b','c','d','e','f'});
int i;
while((i=bais.read())!=-1)
{
System.out.println((char)i);
}
运行结果
a
b
c
d
e
示例2
ByteArrayInputStream bais=new ByteArrayInputStream(new byte[]{'a','b','c','d','e','f'});
byte bytes[]=new byte[10];
bais.read(bytes,0,5);
for (byte b : bytes) {
System.out.print((char)b);
}
输出结果
abcde
ByteArrayOutputStream
概述
ByteArrayOutputStream字节数组输入流 继承与OutputStream抽象类
和字符数组输出流类似 也是一个数据始终储存在内存中的节点流,也可称之为内存流
实际上并没有对外部数据汇进行写入操作 直接采用内存中的数据
主要用于适配以字节输出流为参数的接口
源码分析
成员属性
字节数组 流内容体
protected byte[] buf;
流内容长度
protected int count;
数组的最大可用容量
private static final int MAX_ARRAY_SIZE = 2147483639;
成员方法
构造方法
创建大小为32的ByteArrayOutputStream对象
public ByteArrayOutputStream() {
this(32);
}
创建指定字节数组的大小的对象
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: " + size);
} else {
this.buf = new byte[size];
}
}
确认容量 如果流的容量小于minCapacity 则扩容
private void ensureCapacity(int minCapacity) {
if (minCapacity - this.buf.length > 0) {
this.grow(minCapacity);
}
}
扩容方法
private void grow(int minCapacity) {
int oldCapacity = this.buf.length;
新的容量大小是旧的两倍 左移1位相当于乘以2
int newCapacity = oldCapacity << 1;
处理扩容容量超过整型范围 变为负数的情况
此时扩容大小为minCapacity 由ensureCapacity()方法可知
minCapacity 至少比this.buf.length大
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
如果扩容超过了MAX_ARRAY_SIZE 则调用hugeCapacity()方法
直接扩充到最大容量
if (newCapacity - 2147483639 > 0) {
newCapacity = hugeCapacity(minCapacity);
}
this.buf = Arrays.copyOf(this.buf, newCapacity);
}
扩容到最大许可值
private static int hugeCapacity(int minCapacity) {
如果minCapacity < 0 说明此时minCapacity已经超过数组允许的最大容量
Integer.MAX_VALUE 所以此时抛出内存溢出异常
if (minCapacity < 0) {
throw new OutOfMemoryError();
} else {
扩容后容量是否大于Integer.MAX_VALUE-8 大于则直接扩容到Integer.MAX_VALUE
否则扩容到Integer.MAX_VALUE-8
return minCapacity > 2147483639 ? 2147483647 : 2147483639;
}
}
代码示例
ByteArrayOutputStream baos = new ByteArrayOutputStream();
写入“A”、“B”、“C”三个字母 0x41对应A,0x42对应B,0x43对应C
baos.write(0x41);
baos.write(0x42);
baos.write(0x43);
System.out.printf("baos: %s\n", baos);
获取流内容体大小
int size = baos.size();
System.out.printf("size: %s\n", size);
转换成字节数组
byte[] buf = baos.toByteArray();
String str = new String(buf);
System.out.printf("str=%s\n", str);
输出结果
baos: ABC
size: 3
str=ABC
写入到另一个流中
ByteArrayOutputStream otherbaos = new ByteArrayOutputStream();
baos.writeTo((OutputStream)otherbaos);
System.out.printf("otherbaos: %s\n", otherbaos);
输出结果
otherbaos: ABC