zoukankan      html  css  js  c++  java
  • [六]JavaIO之 ByteArrayInputStream与ByteArrayOutputStream

     

    功能简介

     
    ByteArrayInputStream 和 ByteArrayOutputStream
    提供了针对于字符数组 byte [] 的标准的IO操作方式
     
    image_5b976984_59d4
     
    ByteArrayInputStream将会给一个byte buf[]   提供标准的IO操作方式
     
    ByteArrayOutputStream则是将数据写入到内部的字节数组中
     
     

    ByteArrayInputStream 详解


    功能: 从提供的字节数组中,以IO的行为方式工作,进行读取数据
     

    ByteArrayInputStream字段

    protected byte[] buf 用于保存由该流的创建者提供的 byte 数组
    也就是构造方法传入
    protected int count 个数
    protected int mark 流中当前的标记位置
    构造时默认将 ByteArrayInputStream 对象标记在位置零处
    通过 mark() 方法可将其标记在缓冲区内的另一个位置处
    通过 reset() 方法将当前缓冲区位置设置为此点
    protected int mark = 0;定义时设置了默认值,如果不设置将为0
    protected int pos 要从输入流缓冲区中读取的下一个字符的索引
     
     

    ByteArrayInputStream构造方法

    public ByteArrayInputStream(byte[] buf) 需要传入byte buf[] 字节数组作为他的缓冲区
    当前起始下标 pos  为0
    count为数组长度
    mark位置为0
    image_5b976984_3cbf
    image_5b976984_6c8c
    public ByteArrayInputStream(byte[] buf,
                                int offset,
                                int length)

    传入字节数组以及偏移量和长度
    当前起始下标 pos  为 指定的偏移量
    个数为offset+length 和 buf.length中小的那个
    mark为偏移量起始地址
    可以理解为,这个字节数组偏移量的部分才是数据源,前面都没关系
    image_5b976984_73ec
    image_5b976984_7824
     
     

    read方法

    读取下一个位置的字节
    如果下一个位置 pos小于总个数
    返回pos下标的字节数组数据
    并且pos自增
    image_5b976984_4062
    & 0xff  :
    Java中只有  有符号数,
    类型提升时是按照符号位扩展的
    对于正数,没有什么影响
    对于负数,按照符号位扩展和按照0位扩展区别很大

    按符号位扩展,也就是补符号位,值不变
    按零位扩展,也就是补零时,相当于有符号数转变为无符号数

    所以在数值计算中,直接使用类型提升,数值不变
    而对于编解码时,需要进行转换

    &0xff这种方式就是来确保是按补零扩展
    0xff默认为int型,是十六进制,十进制中表示为255,二进制为32位,后八位为'1111 1111',其他24位均为0
    a & 0xff 操作时,因为a为byte型,所以会将a自动转化为int型(高位补1)
    byte & 0xff操作一般将byte数据转换成int型,最终的数据只有低8位有数据,其他位为0
    简单说就是读取pos下标的元素,返回值为int
      
     

    带参数的read()方法
    将数据读取到b的off位置处

     

    //从流中读取数据到b[] 中,从off开始写,写len长度
    
    public synchronized int read(byte b[], int off, int len) {
    
    if (b == null) {//如果b为null 空指针
    
    throw new NullPointerException();
    
    } else if (off < 0 || len < 0 || len > b.length - off) {//如果偏移量小于0 或者写入长度小于0 或者想要读取的长度小于实际的长度了
    
    throw new IndexOutOfBoundsException();
    
    }
    
    
    
    if (pos >= count) {//如果位置光标已经到了最后了,没有数据可读,返回-1
    
    return -1;
    
    }
    
    
    
    int avail = count - pos;//可用个数为总个数count - 当前位置pos
    
    if (len > avail) {//如果想要读取的len比实际拥有的数据要长,那么只读取实际的个数
    
    len = avail;
    
    }
    
    if (len <= 0) {
    
    return 0;
    
    }
    
    System.arraycopy(buf, pos, b, off, len);//使用本地方法拷贝数据 buf 的pos位置开始拷贝,拷贝len个,到b的off位置
    
    pos += len;//位置光标后移
    
    return len;
    
    }

     
    read方法本质很简单
    就是一个数组,读取一个,就光标移动下一个,pos就是记住位置的变量
    读取的就是指定下标的元素
    image_5b976984_3d24
     

    skip

    image_5b976984_9e0
    image_5b976984_5055
     
     

    available

    本质就是个数组,所以可用个数就是总个数减去下一个字符的索引
    image_5b976984_55e7
     
     

    mark /markSupported /reset

    ByteArrayInputStream支持mark和reset
    而且 很显然,mark方法的输入参数是无效的
    何处调用,何处就是标记点
    调用reset就是pos设置到标记点

    image_5b976984_5d94
    为什么mark 的参数无效?
    很显然,ByteArrayInputStream是操作字符数组的,而且,这个数组不是复制而来的
    是直接通过引用指向的
    也就是说整个的字节数组都在随时可访问的范围内,要这个参数有什么用呢
    mark /markSupported /reset 三连的本质在于提供可重复读的功能,所以对于不可逆的流需要缓存
    此处天然自带可以随时读取某个下标的能力
     

    close

     
    ByteArrayInputStream的根本在于针对给定的某个字节数组,提供IO操作方式的统一形式
    就好像你写了个方法操作字节数组一样,完全不涉及资源
    所以无需关闭任何实质内容
    通过close关闭ByteArrayInputStream之后,如果再次使用这个流
    并不会抛出异常
    当然,流结束了,就不能再继续使用了
     
    所有方法列表
    image_5b976984_53d2
     
     
     

    ByteArrayOutputStream详解

     
    以IO的行为方式工作,将数据写入到内部的字节数组中
     

    ByteArrayOutputStream字段

    protected byte buf[];
    存储数据的缓冲区
    protected int count;
    缓冲区中的有效字节数,每次写入将会写入到buf[count]处
     
     

    ByteArrayOutputStream构造方法

     
    构造方法只是设置内部字节数组这个缓冲区数据的大小
        public ByteArrayOutputStream() ;
    默认长度为32位
    image_5b976984_5f3
    public ByteArrayOutputStream(int size) 只要参数值合法,创建指定个数的字节数组缓冲区
    image_5b976984_3af3
     
     
     

    write

    write是输出,参数都是他的输出内容,只是不同的流输出的目的不一样,此处我们的输出流的目的地是内部的字节数组
    write(int) 将指定的字节写入此 byte 数组输出流
    也就是写入到内部的字节数组中
    write(byte[], int, int) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此 byte 数组输出流
    也就是写入到内部的字节数组中
     
    可以看得出来,他们都有使用 ensureCapacity在必要的时候进行扩展
    扩展的行为是新建一个更大的,然后将原有数组元素全部拷贝过去
    保证空间足够的情况下
    write(int)  就是buf[count] = (byte)b;
    对于write(byte[], int, int)  则是使用System.arraycopy
    image_5b976984_5bfb
     

    writeTo(OutputStream)

     
    因为ByteArrayOutputStream内部维护的是一个字节数组,所以可以直接作为OutputStream中write()方法的参数
    代码很简单,就是讲内部的字节数组,转存到入参指定的输出流中
    相当于把流中的数据重写了一份到另外的输出流
    image_5b976984_123b
     

    toString()

    计算机所有的数据都是二进制存储,最小的单位是字节,字符的编码形式也正是字节
    所以,toString其实就是把字节序列进行解码

    image_5b976984_571f  
    int类型入参的方法,在JDK1.8  已经弃用
    toString()使用平台默认的字符集,通过解码字节将缓冲区内容转换为字符串
    toString(String charsetName)   使用指定的 charsetName,通过解码字节将缓冲区内容转换为字符串
     
     
     

    reset()

    reset是重置的意思,ByteArrayOutputStream 使用buf[] 存储数据,使用count指示位置
    所以想要重新使用现在的缓冲区,抛弃原来所有的,只需要将count清零,每次的数据重新从0开始写入字节数组即可
    image_5b976984_7677
    反正我们知道现在总共有多少有效字节,原来写入到buf中的可能多于count的那些字节就放着好了,我们也不去使用
     

    size()

    count就是一直用来记录有效个数的,所以直接返回count就是实际的size
    image_5b976984_1f98
     
     

    toByteArray()

    转换为字节数组,它本身就是一个字节数组
    所以转换比较简单,只需要创建一个大小相同的字节数组,并且将数据拷贝过去即可
    image_5b976984_5b2a
     

    close()

    ByteArrayOutputStream 写入的是自己内部的字节数组
    属于内存数据,不涉及任何资源,所以close不需要做什么
    image_5b976985_5e3f
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    Mybatis和Spring整合也是能用BatchExecutor的
    与Spring整合的Mybatis没法真正使用BatchExecutor
    Mybatis和Spring整合后sqlsession啥时候关闭的
    Mybatis和Spring的整合原理
    Mybatis是怎么执行一条语句的
    8.11查询结果排序
    8.10、11(select分组和过滤)()
    8.7、8、9(select语句基本用法)(select语句基本运算符)(select聚合查询)
    8.4SQL(DML数据操作语言)-(insert插入数据)(updata更新数据),(delete数据)
    8.2数据库DDL语言(即数据库定义语言)(命名规则以及数据类型)
  • 原文地址:https://www.cnblogs.com/noteless/p/9627822.html
Copyright © 2011-2022 走看看