资讯专栏INFORMATION COLUMN

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

oujie / 1353人阅读

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

(1)属性内容:属性内容相较输入流的会有存放数据的缓冲区,也就是字节数组;
count:写操作的时候的计数,也可以算作数据的大小

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

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

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

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

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

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

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

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

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

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(32);
    }
    //创建指定大小的缓冲数组空间
    public MyByteArrayOutputStream(int size) {
        if(size<0){
            throw new IllegalArgumentException("size 值必须大于0"+size);
        }
        buffer = new byte[size];
    }
    
    //输出流写入一个int b :即将数据写到缓冲数组中
    public synchronized void write(int b){
        //每次写数据前判断当前缓冲数组空间是否够写入,不够则进行扩容
        ensureCapacity(counts+1);
        buffer[counts] = (byte)b;
        //统计写入的大小
        counts+=1;
    }

    //从指定的字节数组向输出流中写数据,可以指定数组中的啥位置开始写入,和写多少
    public synchronized void write(byte[] b,int offset,int length){
        if(b==null){
            throw new NullPointerException();
        }else if((offset < 0) ||(b.length buffer.length){
            growCapacity(capacity);
        }
    }
    
    //扩容方法:两倍当前容量进行扩容,如果两倍容量还小于需要的容量,则使用需要的容量,当然最大不能超过数组的最大容量
    private void growCapacity(int capacity){
        int oldCapacity = buffer.length;
        int newCapacity = oldCapacity << 1;
        if(newCapacity < capacity){
            newCapacity = capacity;
        }
        if(newCapacity < 0){
            if(capacity<0){
                throw new IndexOutOfBoundsException("增加的容量不正常");
            }
            newCapacity=Integer.MAX_VALUE;
        }
        buffer = Arrays.copyOf(buffer, newCapacity);
    }
    
    //重置:将写入的位置设置为0,这样就可以从0位置写数据,重置后缓冲数组中可能存在之前的数据
    public synchronized void reset(){
        counts = 0;
    }
}
4.最后召唤神兽
/**
 *
 *                                                    __----~~~~~~~~~~~------___
 *                                   .  .   ~~//====......          __--~ ~~
 *                   -.            \_|//     |||  ~~~~~~::::... /~
 *                ___-==_       _-~o~  /    |||              _/~~-
 *        __---~~~.==~||=_    -_--~/_-~|-   |           _/~
 *    _-~~     .=~    |  -_    "-~7  /-   /  ||          /
 *  .~       .~       |    -_    /  /-   /   ||         /
 * /  ____  /         |      ~-_/  /|- _/   .||        /
 * |~~    ~~|--~~~~--_      ~==-/   | ~--===~~        .
 *          "         ~-|      /|    |-~~~       __--~~
 *                      |-~~-_/ |    |   ~\_   _-~            /
 *                           /       \__   /~                \__
 *                       _--~ _/ | .-~~____--~-/                  ~~==.
 *                      ((->/~   ".|||" -_|    ~~-/ ,              . _||
 *                                 -_     ~      ~~---l__i__i__i--~~_/
 *                                 _-~-__   ~)  --______________--~~
 *                               //.-~~~-~_--~- |-------~~~~~~~~
 *                                      //.-~~~--
 *                               神兽保佑
 *                              代码无BUG!

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/68021.html

相关文章

  • 我的阿里之路+Java面经考点

    摘要:我的是忙碌的一年,从年初备战实习春招,年三十都在死磕源码,三月份经历了阿里五次面试,四月顺利收到实习。因为我心理很清楚,我的目标是阿里。所以在收到阿里之后的那晚,我重新规划了接下来的学习计划,将我的短期目标更新成拿下阿里转正。 我的2017是忙碌的一年,从年初备战实习春招,年三十都在死磕JDK源码,三月份经历了阿里五次面试,四月顺利收到实习offer。然后五月怀着忐忑的心情开始了蚂蚁金...

    姘搁『 评论0 收藏0
  • Java IO学习笔记四

    摘要:此类中的方法在关闭此流后仍可被调用,而不会产生任何。主要的功能是从缓冲区读取字节构造函数创建一个,使用作为其缓冲区数组。缓冲区会随着数据的不断写入而自动增长。 内存操作流 之前的所有的流操作都是针对文件的,但是有时候只是想要实现数据间转换,此时如果我们想要创建一个文件然后再删除文件,那样显得有点麻烦,因此此时的内存操作流就显得很适合这类的操作,因为它只是在内存中存储,并不会真正的创建文...

    oliverhuang 评论0 收藏0
  • java poi 在excel中插入图片

    摘要:中导出数据是常见的功能,最近遇到一个需求是在中插入图片。处理及其他微软办公系列软件常用的就是,它也是支持图片插入的。 java web中导出excel数据是常见的功能,最近遇到一个需求是在excel中插入图片。处理excel及其他微软办公系列软件常用的就是apache poi,它也是支持图片插入的。插入图片最主要的用到HSSFClientAnchor,文档介绍如下:public HSS...

    robin 评论0 收藏0
  • 慕课网_《Spring Boot热部署》学习总结

    时间:2017年12月01日星期五说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com 教学源码:无 学习源码:https://github.com/zccodere/s... 第一章:课程介绍 1-1 课程介绍 热部署的使用场景 本地调式 线上发布 热部署的使用优点 无论本地还是线上,都适用 无需重启服务器:提高开发、调式效率、提升发布、运维效率、降低运维成本 前置...

    Channe 评论0 收藏0
  • IOByteArrayOutputStream源码分析

    摘要:一共有两个属性存放数据的字节数组的索引方法判断的容量是否够存放数据如果容量不够了,则扩容加倍扩容已经最大容量扩展到最大容量另一个方法上面已经分析通过数组拷贝将的数据复制到中去设置当前数据的长度方法直接将设置为,那么下次在写数据的 ByteArrayOutputStream一共有两个属性 protected byte buf[];//存放数据的字节数组 protected...

    GitCafe 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<