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;

理解:

源码:

public synchronized int read() { 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操作

源码:

public void close() throws IOException { }

理解:

  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;

public ByteArrayOutputStream() { this(32); }

  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数组的数据源角色和目的源角色互调下而已

源码:

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

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

理解:

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

源码:

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. }

结果:

  1. ASCII码的十进制: 100
  2. ASCII码的十进制: 101
  3. ASCII码的十进制: 102
  4. ASCII码的十进制: 103
  5. ASCII码的十进制: 104
  6. bos的内置buf数据: defgh

6. 参考:

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

Java I/O系列(二)ByteArrayInputStream与ByteArrayOutputStream源码分析及理解的更多相关文章

  1. Spring源码系列(二)--bean组件的源码分析

    简介 spring-bean 组件是 Spring IoC 的核心,我们可以使用它的 beanFactory 来获取所需的对象,对象的实例化.属性装配和初始化等都可以交给 spring 来管理. 本文 ...

  2. java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)

    我们以ByteArrayInputStream,拉开对字节类型的“输入流”的学习序幕.本章,我们会先对ByteArrayInputStream进行介绍,然后深入了解一下它的源码,最后通过示例来掌握它的 ...

  3. java基础解析系列(十)---ArrayList和LinkedList源码及使用分析

    java基础解析系列(十)---ArrayList和LinkedList源码及使用分析 目录 java基础解析系列(一)---String.StringBuffer.StringBuilder jav ...

  4. 一步步实现windows版ijkplayer系列文章之二——Ijkplayer播放器源码分析之音视频输出——视频篇

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  5. 图解Janusgraph系列-图数据底层序列化源码分析(Data Serialize)

    图解Janusgraph系列-图数据底层序列化源码分析(Data Serialize) 大家好,我是洋仔,JanusGraph图解系列文章,实时更新~ 图数据库文章总目录: 整理所有图相关文章,请移步 ...

  6. Eureka 系列(04)客户端源码分析

    Eureka 系列(04)客户端源码分析 [TOC] 0. Spring Cloud 系列目录 - Eureka 篇 在上一篇 Eureka 系列(01)最简使用姿态 中对 Eureka 的简单用法做 ...

  7. Java 序列化和反序列化(三)Serializable 源码分析 - 2

    目录 Java 序列化和反序列化(三)Serializable 源码分析 - 2 1. ObjectStreamField 1.1 数据结构 1.2 构造函数 2. ObjectStreamClass ...

  8. Java 集合系列(四)—— ListIterator 源码分析

    以脑图的形式来展示Java集合知识,让零碎知识点形成体系 Iterator 对比   Iterator(迭代器)是一种设计模式,是一个对象,用于遍历集合中的所有元素.  Iterator 包含四个方法 ...

  9. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

随机推荐

  1. jsp页面乱码

  2. Linux VPS主机利用Crontab实现定时重启任务

    第一.安装Crontab可执行环境 一般的VPS/服务器是支持的,但是有些可能没有支持就需要我们来给予安装. A - centos系统 #安装Crontab yum install vixie-cro ...

  3. 02.php面向对象——构造方法&析构方法

    <?php //自己写的构造方法 class Computer{ public function Computer(){ echo '构造方法'; } } new Computer();//这样 ...

  4. 新安装的Apache和php,测试可以解析phpinfo,但是无法打开drupal网站

    没有去掉php.ini中mysql相关的一些扩展的注释

  5. 30分钟掌握ES6/ES2015核心内容[上和下], 不错的说

    ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015. 也就是说,ES6就是ES2015. ...

  6. python学习笔记之——正则表达式

    1.re模块 Python通过re模块提供对正则表达式的支持,re 模块使 Python 语言拥有全部的正则表达式功能.使用re的一般步骤是先将正则表达式的字符串形式编译为Pattern实例,然后使用 ...

  7. JavaScript中map函数和filter的简单举例

    JavaScript的数组迭代器函数map和filter,可以遍历数组时产生新的数组,和python的map函数很类似 1> filter是满足条件的留下,是对原数组的过滤:2> map则 ...

  8. .net core系列之《.net平台历程介绍以及.net framework和.net core对比》

    一..Net平台的背景 1.2010之前 的PC时代的时候,互联网规模还不是特别庞大,以静态编译式语言为代表的JAVA和.Net没什么太大区别,.net以windows自居. 2.2010年以JAVA ...

  9. ASP.net Substitution 页面缓存而部分不缓存的实现方法

    在ASP.NET中要实现部分内容非缓存,而其它的都需要缓存输出,可以使用Substitution控件实现. <%@ Page Language="C#" AutoEventW ...

  10. 在Android Studio2.3中配置OpenCV4Android SDK

    在Android Studio2.3中配置OpenCV4Android SDK 一,OpenCV4Android下载地址 [2.4.11]http://onhdz331f.bkt.clouddn.co ...