您的位置:首页 > 编程语言 > Java开发

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!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐