天天看点

JAVA IO源码学习系列一(ByteArrayOutputStream)

介绍

1. 输出流:ByteArrayOutputStream

上一篇简单介绍了输出流的超类OutputStream,也大概的讲述了输出流的作用,本篇就介绍一下,输出流的一种实现,字节数组输出流,该输出流是为了处理字节的基础流,本质上就是写入数据到类中的缓冲字节数组中;
           

2. ByteArrayOutputStream 源代码介绍

(1)属性内容:属性内容相较输入流的会有存放数据的缓冲区,也就是字节数组;

count:写操作的时候的计数,也可以算作数据的大小

// 存储数据的缓冲区(字节数组)。
protected byte buf[];
//缓冲区中的有效字节数(写入的内容大小,也可以看做是位置)
protected int count;
           

(2)构造函数:默认的构造函数会初始化缓冲区大小为32个字节,即缓冲数组的大小为32;

//默认构造函数
    public ByteArrayOutputStream() {
        this();
    }

    //指定的缓冲区大小
    public ByteArrayOutputStream(int size) {
        if (size < ) {
            throw new IllegalArgumentException("Negative initial size: "
                                               + size);
        }
        buf = new byte[size];
    }
           

(3)主要方法:输出流的主要方法当然就是写,ByteArrayOutputStream中有三种写方法,第一是写入一个int 数据以字节的形式存到缓冲数组中,第二个就是写入指定的字节数组,可以指定从该数组的哪个位置开始写,和写多少;最后一个是写到指定的输出流中,相当于继续流,

// 将指定的字节写入此 byte 数组输出流。
public synchronized void write(int b) {
        ensureCapacity(count + );
        buf[count] = (byte) b;
        count += ;
    }
//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流。
public synchronized void write(byte b[], int off, int len) {
        if ((off < ) || (off > b.length) || (len < ) ||
            ((off + len) - b.length > )) {
            throw new IndexOutOfBoundsException();
        }
        ensureCapacity(count + len);
        System.arraycopy(b, off, buf, count, len);
        count += len;
    }
//将此 byte 数组输出流的全部内容写入到指定的输出流参数中
public synchronized void writeTo(OutputStream out) throws IOException {
        out.write(buf, , count);
    }
           
扩容方法:
在上面的写方法中我们可以看到其中还有一个中间处理的方法,也就是扩容的方法,在数据写入的过程中,每次会判断当前的缓冲区容量是否够写入,如果不够就两倍扩容;
           
//判断是否需要扩容
private void ensureCapacity(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - buf.length > )
            grow(minCapacity);
    }

//进行扩容操作
private void grow(int minCapacity) {
        int oldCapacity = buf.length;
        int newCapacity = oldCapacity << ;
        if (newCapacity - minCapacity < )
            newCapacity = minCapacity;
        if (newCapacity < ) {
            if (minCapacity < ) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        buf = Arrays.copyOf(buf, newCapacity);
    }
           

(4)其他方法介绍

reset():重置方法仅仅是将count值设置为0,这样写数据的时候就可以重新从0开始写,此时缓冲区的数据其实还存在;

public synchronized void reset() {
        count = ;
    }
           

size():返回当前写入了多少数据,其实就是count的值;

public synchronized int size() {
        return count;
    }
           

toByteArray():以字节数组的形式返回当前缓冲数组中的数据,当然位置是从0,到count,所以reset操作之后即使缓冲数组中的数据很多,但只显示到count;

public synchronized byte toByteArray()[] {
        return Arrays.copyOf(buf, count);
    }
           

还有toString()的方法:字符串显示,类似toByteArray();

3. 附上自己重写的代码

只实现核心的方法功能,没有继承其他类;

//字节数组输出流
public class MyByteArrayOutputStream {

    //缓冲的字节数组
    protected byte[] buffer;

    //输出流的内容大小,写入的大小
    protected int counts;

    //默认构造初始化时定义32字节大小的缓冲数组空间
    public MyByteArrayOutputStream() {
       this();
    }
    //创建指定大小的缓冲数组空间
    public MyByteArrayOutputStream(int size) {
        if(size<){
            throw new IllegalArgumentException("size 值必须大于0"+size);
        }
        buffer = new byte[size];
    }

    //输出流写入一个int b :即将数据写到缓冲数组中
    public synchronized void write(int b){
        //每次写数据前判断当前缓冲数组空间是否够写入,不够则进行扩容
        ensureCapacity(counts+);
        buffer[counts] = (byte)b;
        //统计写入的大小
        counts+=;
    }

    //从指定的字节数组向输出流中写数据,可以指定数组中的啥位置开始写入,和写多少
    public synchronized void write(byte[] b,int offset,int length){
        if(b==null){
            throw new NullPointerException();
        }else if((offset < ) ||(b.length<offset)|| length <  || (b.length<length+offset)){
            throw new IndexOutOfBoundsException("写入的大小不正常,越界了");
        }
      //每次写数据前判断当前缓冲数组空间是否够写入,不够则进行扩容
        ensureCapacity(counts+length);
       //将指定的数据写入到缓冲数组中
        System.arraycopy(b, offset, buffer, counts, length);
      //统计写入的大小
        counts+=length;

    }

    //将缓冲数组输出流中的数据写入指定的输出流中
    public synchronized void writeTo(OutputStream out) throws IOException{
        //类似回调方法,写入指定输出流中
        out.write(buffer,,counts);

    }

    //返回字节数组:即将当前缓冲数组中的数据以字节数组的形式返回
    public synchronized byte[] toByteArray(){
        return Arrays.copyOf(buffer, counts);
    }
    //返回字符串:即将当前缓冲数组中的数据以字符串的形式返回
    public synchronized String toString(){
        return new String(buffer,,counts);
    }
  //返回字符串:即将当前缓冲数组中的数据以字符串的形式返回,指定了字符集
    public synchronized String toString(String charsetName) throws UnsupportedEncodingException{

        return new String(buffer,,counts,charsetName);
    }

    //返回当前输出流的大小,即缓冲数组中写入的数据
    public synchronized int size(){
        return counts;
    }

    //判断当前是否需要扩容:即比较当前的容量是否大于新增的数量,不够则进行扩容
    private void ensureCapacity(int capacity){

        if(capacity > buffer.length){
            growCapacity(capacity);
        }
    }

    //扩容方法:两倍当前容量进行扩容,如果两倍容量还小于需要的容量,则使用需要的容量,当然最大不能超过数组的最大容量
    private void growCapacity(int capacity){
        int oldCapacity = buffer.length;
        int newCapacity = oldCapacity << ;
        if(newCapacity < capacity){
            newCapacity = capacity;
        }
        if(newCapacity < ){
            if(capacity<){
                throw new IndexOutOfBoundsException("增加的容量不正常");
            }
            newCapacity=Integer.MAX_VALUE;
        }
        buffer = Arrays.copyOf(buffer, newCapacity);
    }

    //重置:将写入的位置设置为0,这样就可以从0位置写数据,重置后缓冲数组中可能存在之前的数据
    public synchronized void reset(){
        counts = ;
    }
}
           

4.最后召唤神兽

/**
 *
 *                                                    __----~~~~~~~~~~~------___
 *                                   .  .   ~~//====......          __--~ ~~
 *                   -.            \_|//     |||\\  ~~~~~~::::... /~
 *                ___-==_       _-~o~  \/    |||  \\            _/~~-
 *        __---~~~.==~||\=_    -_--~/_-~|-   |\\   \\        _/~
 *    _-~~     .=~    |  \\-_    '-~7  /-   /  ||    \      /
 *  .~       .~       |   \\ -_    /  /-   /   ||      \   /
 * /  ____  /         |     \\ ~-_/  /|- _/   .||       \ /
 * |~~    ~~|--~~~~--_ \     ~==-/   | \~--===~~        .\
 *          '         ~-|      /|    |-~\~~       __--~~
 *                      |-~~-_/ |    |   ~\_   _-~            /\
 *                           /  \     \__   \/~                \__
 *                       _--~ _/ | .-~~____--~-/                  ~~==.
 *                      ((->/~   '.|||' -_|    ~~-/ ,              . _||
 *                                 -_     ~\      ~~---l__i__i__i--~~_/
 *                                 _-~-__   ~)  \--______________--~~
 *                               //.-~~~-~_--~- |-------~~~~~~~~
 *                                      //.-~~~--\
 *                               神兽保佑
 *                              代码无BUG!