JAVA IO源码学习系列一(ByteArrayOutputStream)
2017-11-16 20:17
323 查看
介绍
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<offset)|| length < 0 || (b.length<length+offset)){ throw new IndexOutOfBoundsException("写入的大小不正常,越界了"); } //每次写数据前判断当前缓冲数组空间是否够写入,不够则进行扩容 ensureCapacity(counts+length); //将指定的数据写入到缓冲数组中 System.arraycopy(b, offset, buffer, counts, length); //统计写入的大小 counts+=length; } //将缓冲数组输出流中的数据写入指定的输出流中 public synchronized void writeTo(OutputStream out) throws IOException{ //类似回调方法,写入指定输出流中 out.write(buffer,0,counts); } //返回字节数组:即将当前缓冲数组中的数据以字节数组的形式返回 public synchronized byte[] toByteArray(){ return Arrays.copyOf(buffer, counts); } //返回字符串:即将当前缓冲数组中的数据以字符串的形式返回 public synchronized String toString(){ return new String(buffer,0,counts); } //返回字符串:即将当前缓冲数组中的数据以字符串的形式返回,指定了字符集 public synchronized String toString(String charsetName) throws UnsupportedEncodingException{ return new String(buffer,0,counts,charsetName); } //返回当前输出流的大小,即缓冲数组中写入的数据 public synchronized int size(){ return counts; } //判断当前是否需要扩容:即比较当前的容量是否大于新增的数量,不够则进行扩容 private void ensureCapacity(int capacity){ if(capacity > 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!
相关文章推荐
- JAVA IO源码学习系列一(OutputStream)
- JAVA IO源码学习系列之ByteArrayInputStream
- JAVA IO源码学习系列之InputStream
- java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
- java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
- java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)
- java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)
- java io系列13之 BufferedOutputStream(缓冲输出流)的认知、源码和示例
- java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
- java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
- Java 7 源码学习系列(三)——BigInteger
- java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例
- java IO 流的学习(我们到底能走多远系列1)
- java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
- java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
- Java 源码学习线路————_先JDK工具包集合_再core包,也就是String、StringBuffer等_Java IO类库
- java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例
- java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例
- java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
- java io系列13之 BufferedOutputStream(缓冲输出流)的认知、源码和示例