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