简介

ByteArrayInputStream 是字节数组输入流,它继承于InputStream。
它的内部数据存储结构就是字节数组。

ByteArrayOutputStream是字节数组输出流,它继承于OutputStream。
它的内部数据存储结构也是字节数组。

源码分析

InputStream

在分析ByteArrayInputStream之前,应该先看InputStream,父类InputStream是ByteArrayInputStream的父类,主要实现了读取和跳跃的方法。

public abstract class InputStream implements Closeable {

    // 最大可跳过的字节数
private static final int MAX_SKIP_BUFFER_SIZE = 2048; // 向后读取一个字节
public abstract int read() throws IOException; // 将字节流中的数据装到字节数组的0位开始的位置
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
} // 将字节流中的数据装到字节数组的指定位置当中
public int read(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
} int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c; int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
} // 跳过输入流中的n个字节
public long skip(long n) throws IOException { long remaining = n;
int nr; if (n <= 0) {
return 0;
} int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
} return n - remaining;
} // 是否还有
public int available() throws IOException {
return 0;
} // 关闭流
public void close() throws IOException {} // 标记
public synchronized void mark(int readlimit) {} // 重置
public synchronized void reset() throws IOException {
throw new IOException("mark/reset not supported");
} // 是否支持标记方法
public boolean markSupported() {
return false;
} }

ByteArrayInputStream

public
class ByteArrayInputStream extends InputStream { // 字节数组,存储数据
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;
} // 读取单个字节
public synchronized int read() {
// 这里& 0xff的操作是为了只取低八位
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;
}
// 剩余长度
int avail = count - pos;
// 如果要求读的长度大于剩余长度,就设置读的长度为剩余长度
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
// 底层采用的
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
} // 跳过指定长度的字节
public synchronized long skip(long n) {
long k = count - pos;
if (n < k) {
// 如果是负数那么就不动
// 取n和k最小的一个
k = n < 0 ? 0 : n;
}
// 移动k位
pos += k;
return k;
} // 是否还有数据可以读
public synchronized int available() {
return count - pos;
} // 是否支持标记功能
public boolean markSupported() {
return true;
} // 标记当前位置,这个传入参数是个摆设
public void mark(int readAheadLimit) {
mark = pos;
} // 重置,也就是将当前指针指向之前mark的位置
public synchronized void reset() {
pos = mark;
} // 关闭字节流
public void close() throws IOException {
} }

OutputStream

OutputStream是ByteArrayOutputStream的父类,先看看它的源码。

很短,实现了Closeable, Flushable。

public abstract class OutputStream implements Closeable, Flushable {

    public abstract void write(int b) throws IOException;

    public void write(byte b[]) throws IOException {
write(b, 0, b.length);
} public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
} public void flush() throws IOException {
} public void close() throws IOException {
} }

ByteArrayOutputStream

public class ByteArrayOutputStream extends OutputStream {

	// 存储数据的字节数组
protected byte buf[]; // 数组长度
protected int count; // 默认构造,默认大小是32
public ByteArrayOutputStream() {
this(32);
} // 初始化长度的构造
public ByteArrayOutputStream(int size) {
if (size < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ size);
}
// 初始化一个数组对象
buf = new byte[size];
} // 查看是否需要扩容
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
if (minCapacity - buf.length > 0)
grow(minCapacity);
} // 数组的最大长度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 扩容
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = buf.length;
// 默认先扩容两倍
int newCapacity = oldCapacity << 1;
// 如果还是不够就将容量扩到需求的大小
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
// 边界判断
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// 将旧数组复制到新数组
buf = Arrays.copyOf(buf, newCapacity);
} // 边界判断
private static int hugeCapacity(int minCapacity) {
if (minCapacity < 0) // overflow
throw new OutOfMemoryError();
return (minCapacity > MAX_ARRAY_SIZE) ?
Integer.MAX_VALUE :
MAX_ARRAY_SIZE;
} // 写入单个字节
public synchronized void write(int b) {
// 先判断是否需要扩容
ensureCapacity(count + 1);
// 写入字节
buf[count] = (byte) b;
// 增加可用长度
count += 1;
} // 写入字节数组
public synchronized void write(byte b[], int off, int len) {
if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) - b.length > 0)) {
throw new IndexOutOfBoundsException();
}
ensureCapacity(count + len);
// 将数组整个复制过去
System.arraycopy(b, off, buf, count, len);
count += len;
} // 将当前Stream输出到指定的Streamz中
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);
} @Deprecated
// 获取高位的字节
public synchronized String toString(int hibyte) {
return new String(buf, hibyte, 0, count);
} public void close() throws IOException {
} }

总结

输入输出流的本质就是一个中间缓存器,暂时将数据放在中间的缓存区,然后根据指定要求输出或如输入。

ByteArrayInputStream 特点

  • 数组实现中间缓存;
  • 修改和读取操作都是线程安全了,因为加了synchronized;
  • 具有标记回读的功能,就是可以先读后面的数据,然后经过重置,再去读前面标记位置的数据。

ByteArrayOutputStream特点

  • 数组实现中间缓存;
  • 修改读取也是具有线程安全的;
  • 具有扩容功能,应为想要写入的数据是增长的,在写入之前,就会进行依次扩容判断;
  • 默认的初始大小是32,如果一个个数据写入的扩容,每次是扩一倍的大小;
  • 可以写入到其他的输出流上。

最新文章

  1. PHP 面向对象编程和设计模式 (5/5) - PHP 命名空间的使用及名称解析规则
  2. Java学习笔记(三)
  3. note
  4. 第十六回 IoC组件Unity续~批量动态为Unity添加类型和行为
  5. Emit学习(3) - OpCodes - 循环和异常
  6. CSS布局——居中
  7. 230. Kth Smallest Element in a BST
  8. js之json
  9. 设计模式 - command
  10. spring注解方式实现定时器,并且cron表达式中不识别L的方法
  11. java学会需要掌握的知识(来源网上。。)
  12. Unix/Linux环境C编程入门教程(35) 编程管理系统中的组
  13. 局域网内IP冲突怎么办
  14. Linux Shell常用技巧(二) grep
  15. 公司需求知识自学-Oracle的Package的作用及用法
  16. 15 Actionbar的显示和隐藏
  17. Oracle 迁移某用户的数据到Sql Server
  18. TSL 访问器
  19. JavaScript的函数声明与函数表达式的区别
  20. 正则RegExp的懒惰性和贪婪性; 分组捕获;

热门文章

  1. linux系统中离线安装python3.7过程记录
  2. 关于多线程--网络编程 -- 注解反射的一点笔记(JAVA篇)
  3. arm-linux 修改rootfs登录名和密码
  4. Git本地仓库和远程仓库冲突解决
  5. 众所周知,B站并不是个学习网站
  6. php在线预览pdf文件
  7. 面试阿里,腾讯90%会被问到的zookeeper,把这篇文章看完就够了。
  8. 巧妙运用Camtasia制作爱豆的动感影集
  9. Echo Delay:FL中好用的声音制作处理方法
  10. 【VUE】8.VUEX核心概念