• Java I/O系列(二)ByteArrayInputStream与ByteArrayOutputStream源码分析及理解


    1. ByteArrayInputStream

    定义


     继承了InputStream,数据源是内置的byte数组buf,那read ()方法的使命(读取一个个字节出来),在ByteArrayInputStream就是简单的通过定向的取buf元素实现的

    核心源码理解


    源码:

    1 public ByteArrayInputStream(byte buf[], int offset, int length) {
    2         this.buf = buf;
    3         this.pos = offset;
    4         this.count = Math.min(offset + length, buf.length);
    5         this.mark = offset;
    6     }

    理解:

    1. 构造ByteArrayInputStream, 直接将外部的byte数组作为内置的buf,作为被读取的数据源

    源码:

     1     // 存放数据的地方
     2     protected byte buf[];
     3 
     4     // 下一个要被读取的位置,即等待读取的位置
     5     protected int pos;
     6 
     7     // 标记pos的位置
     8     protected int mark = 0;
     9 
    10     // 实际能被读取的byte的数量
    11     protected int count;

    理解:

    源码:

     1 public synchronized int read() { 2 return (pos < count) ? (buf[pos++] & 0xff) : -1;} 

    理解:

    1. 该方法是被synchronized修饰的,其它方法也是,故ByteArrayInputStream是线程安全的

    2. byte类型和0xff做与运算,转成byte的无符号类型(0-255),上节也说明过

    源码:

     1 public synchronized int read(byte b[], int off, int len) {
     2         if (b == null) {
     3             throw new NullPointerException();
     4         } else if (off < 0 || len < 0 || len > b.length - off) {
     5             throw new IndexOutOfBoundsException();
     6         }
     7 
     8         if (pos >= count) {
     9             return -1;
    10         }
    11 
    12         int avail = count - pos;
    13         if (len > avail) {
    14             len = avail;
    15         }
    16         if (len <= 0) {
    17             return 0;
    18         }
    19         System.arraycopy(buf, pos, b, off, len);
    20         pos += len;
    21         return len;
    22     }

    理解:

      1. 因为数据源是byte数组,目的源也是byte数组,故直接采用了数组copy的方法,写入到b数组中

    源码:

    1 public synchronized long skip(long n) {
    2         long k = count - pos;
    3         if (n < k) {
    4             k = n < 0 ? 0 : n;
    5         }
    6 
    7         pos += k;
    8         return k;
    9     }

    理解:

      1. 通过调整pos的值,来实现skip操作

    源码:

     1 public void close() throws IOException { 2 } 

    理解:

      1. 空实现,故close后并不会有任何影响,还是可以继续往外读的

     2. ByteArrayOutputStream

    定义


     继承了OutputStream,目的源是内置的byte数组buf,write()方法是一个个字节写入到buf中(其实就是简单到buf[i]=b,这种赋值操作)

    核心源码理解


    源码:

    1 // 目的源,存储数据的地方 
    2 protected byte buf[];
    3 
    4 // buf中实际的byte数(不是buf.length)
    5  protected int count;

     1 public ByteArrayOutputStream() { 2 this(32); 3 } 

    1  public ByteArrayOutputStream(int size) {
    2         if (size < 0) {
    3             throw new IllegalArgumentException("Negative initial size: "
    4                                                + size);
    5         }
    6         buf = new byte[size];
    7     }

     理解:

      1. 默认构造ByteArrayOutputStream的buf长度是32;可以指定存储数据的buf数组的长度

    源码:

    1 public synchronized void write(int b) {
    2         ensureCapacity(count + 1);
    3         buf[count] = (byte) b;
    4         count += 1;
    5     }

    理解:

      1. 重写了InputStream的write(int b) 方法,直接给buf某个元素赋值;

      2. 被synchronized修饰(包括其它方法),因此ByteArrayOutputStream是线程安全的

      3. ensureCapacity,是判断当前的容量和buf.length的大小,如果超过了buf.length,则会对buf进行扩容(申请一个更大的数组,通过Arrays.copyOf方法进行旧元素copy,让buf指向这个新的大数组)

    源码:

    1 public synchronized void write(byte b[], int off, int len) {
    2         if ((off < 0) || (off > b.length) || (len < 0) ||
    3             ((off + len) - b.length > 0)) {
    4             throw new IndexOutOfBoundsException();
    5         }
    6         ensureCapacity(count + len);
    7         System.arraycopy(b, off, buf, count, len);
    8         count += len;
    9     }

     理解:

      1. 参数b数组是数据源,待被读取的字节数组,由于目的源是内置的字节数组buf,直接通过数组copy的形式完成写入操作

      2. 与ByteArrayInputStream的read(byte b[], int off, int len)几乎一样,只是内置的buf数组和参数b数组的数据源角色和目的源角色互调下而已

    源码:

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

    public synchronized String toString() {
            return new String(buf, 0, count);
        }
    1 public synchronized String toString(String charsetName)
    2         throws UnsupportedEncodingException
    3     {
    4         return new String(buf, 0, count, charsetName);
    5     }

     理解:

      1. 这三个方法都是取出内置的buf数据,比较容易理解

    源码:

     1 public void close() throws IOException {  } 

    理解:

      1. close后还是可以继续写入的

    3. 总结:

    1. 实现了mark与reset方法,mark方法中让mark=pos,reset时让pos=mark,比较容易理解

    4. 问题:

     1. 欢迎大家提出问题,共同交流学习!

    5. 示例: 

     1     /**
     2      * ByteArrayInputStream的read是从自己内置的buf中读,read的数据源是buf
     3      * ByteArrayOutputStream的write是写入到自己内置的buf中去,write的目的源是buf
     4      */
     5     public static void test1() {
     6         // 对应abcddefghijklmnopqrsttuvwxyz的ASCII码十六进制分别为
     7         byte[] bytes = new byte[] { 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
     8                 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A
     9         };
    10 
    11         // 0x64, 0x65, 0x66, 0x67, 0x68
    12         ByteArrayInputStream bis = new ByteArrayInputStream(bytes, 3, 5);
    13         ByteArrayOutputStream bos = new ByteArrayOutputStream(); //默认内置的buf长度为32哦
    14         int b = 0;
    15         while((b = bis.read()) != -1) {
    16             System.out.println("ASCII码的十进制: " + b);
    17 
    18             //将读到的字节,再写入到bos中的内置buf中
    19             bos.write(b);
    20         }
    21 
    22         // 虽然close都是空实现,但养成一个关闭资源(比如流,连接)的习惯
    23         try {
    24             bis.close();
    25             bos.close();
    26         } catch (IOException e) {
    27             e.printStackTrace();
    28         }
    29 
    30         System.out.println("bos的内置buf数据: " + bos.toString());
    31     }

    执行:

    1 public static void main(String args[]) {
    2     test1();
    3 }

    结果:

    ASCII码的十进制: 100
    ASCII码的十进制: 101
    ASCII码的十进制: 102
    ASCII码的十进制: 103
    ASCII码的十进制: 104
    bos的内置buf数据: defgh

    6. 参考:

     1. http://www.cnblogs.com/skywang12345/p/io_03.html

  • 相关阅读:
    Linux下c开发 之 线程通信(转)
    mount -t nfs 的使用
    window共享linux下的文件 samba
    C/C++ 的使用
    php获取格式时间和时间戳
    php压缩文件夹
    php递归删除文件夹
    php生成文件夹(递归生成)
    QQ音乐API分析记录
    $(this)与this的区别
  • 原文地址:https://www.cnblogs.com/nolan4954/p/9265170.html
Copyright © 2020-2023  润新知