[重学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