Java IO 系列源码分析——ByteArrayInputStream和ByteArrayOutputStream

来源:互联网 发布:2017最新一手数据 编辑:程序博客网 时间:2024/05/17 21:44

ByteArrayInputStream是字节数组输入流,继承于InputStream,它内部包含一个缓冲区,该缓冲区存有从输入流中读取的字节。ByteArrayInputStream内部还额外定义了一个计数器,用于记录read()方法读取的下一个字节的位置
ByteArrayOutputStream是字节数组输出流,继承于OutputStream,它内部同样包含一个缓冲区,ByteArrayOutputStream中的数据被写入该缓冲区,缓冲区的大小会随着写入数据的增加而增长。我们可以通过ByteArrayOutputStreamtoByteArraytoString方法来获取数据。
下面我们就分别对ByteArrayInputStreamByteArrayOutputStream源码进行学习。
1. ByteArrayInputStream源码分析(基于jdk1.8.0_66)

Package java.io;public class ByteArrayInputStream extends InputStream {     //内部缓冲区,保存字节输入流数据    protected byte buf[];     //计数器,标记下一次从内部缓冲区读取的位置     //范围:[0, count]    protected int pos;     //标记的索引,构造器初始化时默认为0     //调用mark方法可以标记到其他位置,调用reset方法    protected int mark = 0;    //字节流的长度    protected int count;    //构造一个缓冲区为buf的字节流    public ByteArrayInputStream(byte buf[]) {        this.buf = buf;        this.pos = 0; //设置下一次要被读取的索引为0        this.count = buf.length; //设置字节流长度为buf的长度    }    //构造一个缓冲区为buf的字节流,并从offset开始读取数据,读取的长度最长不超过length    public ByteArrayInputStream(byte buf[], int offset, int length) {        this.buf = buf;        this.pos = offset;//设置下一次要被读取的索引为offset        this.count = Math.min(offset + length, buf.length);        this.mark = offset;//设置标记的索引为offset    }    //实现了InputStream的read方法,读取下一个字节    public synchronized int read() {        return (pos < count) ? (buf[pos++] & 0xff) : -1;    }    //将字节流中最多len个字节写入到数组b中,写入位置从下标off开始计算。    //返回实际写入的字节数    public synchronized int read(byte b[], int off, int len) {        if (b == null) {            throw new NullPointerException();        } else if (off < 0 || len < 0 || len > b.length - off) {            throw new IndexOutOfBoundsException();        }        //字节流中无数据可读        if (pos >= count) {            return -1;        }        int avail = count - pos; //字节流中可以被读取的字节数据长度        if (len > avail) {            len = avail;        }        if (len <= 0) {            return 0;        }        System.arraycopy(buf, pos, b, off, len);        pos += len;        return len;    }    //跳过字节流中最多n个字节,返回实际跳过的字节数    public synchronized long skip(long n) {        long k = count - pos; //获取字节流中可以读取或者跳过的字节数目        if (n < k) {            k = n < 0 ? 0 : n;        }        pos += k;        return k;    }    //获取字节流中可以读取的字节数目    public synchronized int available() {        return count - pos;    }    //测试该数据流是否支持标记    //ByteArrayInputStream支持标记    public boolean markSupported() {        return true;    }    //标记当前位置,readAheadLimit暂时没有实际意义    public void mark(int readAheadLimit) {        mark = pos;    }    //重置当前流的读取位置为最后一次调用mark方法标记的位置    public synchronized void reset() {        pos = mark;    }    public void close() throws IOException {    }}
  1. ByteArrayOutputStream源码分析
public class ByteArrayOutputStream extends OutputStream {    //保存字节数组输出流数据的数组    protected byte buf[];    //数组中字节的数目,计数器    protected int count;    //构造一个新的字节数组输出流,默认数组容量为32    public ByteArrayOutputStream() {        this(32);    }     //构造一个新的字节数组输出流,默认数组容量为size    public ByteArrayOutputStream(int size) {        if (size < 0) {            throw new IllegalArgumentException("Negative initial size: "                                               + size);        }        buf = new byte[size];    }     //确保数组容量,若数组容量小于minCapacity则扩展容量    private void ensureCapacity(int minCapacity) {        // overflow-conscious code        if (minCapacity - buf.length > 0)            grow(minCapacity);    }    //数组允许分配的最大容量    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    //增加数组容量    private void grow(int minCapacity) {        // overflow-conscious code        int oldCapacity = buf.length;        int newCapacity = oldCapacity << 1;//新的数组容量为旧数组容量的2倍        if (newCapacity - minCapacity < 0)            newCapacity = minCapacity;        if (newCapacity - MAX_ARRAY_SIZE > 0)            newCapacity = hugeCapacity(minCapacity);        buf = Arrays.copyOf(buf, newCapacity);    }    //若数组容量超过MAX_ARRAY_SIZE, 则根据minCapacity和Intege.MAX_VALUE大小来确定数组是否扩容    private static int hugeCapacity(int minCapacity) {        if (minCapacity < 0) // overflow            throw new OutOfMemoryError();        return (minCapacity > MAX_ARRAY_SIZE) ?            Integer.MAX_VALUE :            MAX_ARRAY_SIZE;    }    /**     * Writes the specified byte to this byte array output stream.     *     * @param   b   the byte to be written.     */     //将指定字节b写入到该字节数组输出流,计数器+1    public synchronized void write(int b) {        ensureCapacity(count + 1);        buf[count] = (byte) b;        count += 1;    }     //将数组b中从offset开始的len长度字节写入该字节数组输出流。计数器+len    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;    }     //将该字节数组输出流中的字节数据全部写入到指定的输出流中    public synchronized void writeTo(OutputStream out) throws IOException {        out.write(buf, 0, count);    }     //将计数器置零,以便向该字节数组输出流重新写入数据    public synchronized void reset() {        count = 0;    }     //将该字节数组输出流数据写入到一个新的字节数组,并返回这个新的数组    public synchronized byte toByteArray()[] {        return Arrays.copyOf(buf, count);    }     //返回字节数组输出流当前的计数器的数值    public synchronized int size() {        return count;    }    public synchronized String toString() {        return new String(buf, 0, count);    }    public synchronized String toString(String charsetName)        throws UnsupportedEncodingException    {        return new String(buf, 0, count, charsetName);    }    @Deprecated    public synchronized String toString(int hibyte) {        return new String(buf, hibyte, 0, count);    }    public void close() throws IOException {    }}
  1. ByteArrayInputStream示例 (测试基于 junit-4.12)
package test.io;import org.junit.Before;import org.junit.Test;import java.io.ByteArrayInputStream;import java.util.Arrays;public class ByteArrayInputStreamTest {    private static final int LEN = 6;    private static final byte[] byteArray = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};    private ByteArrayInputStream bais;    @Before    public void beforeTest(){        //创建一个缓冲区为byteArray的字节数组输入流        bais = new ByteArrayInputStream(byteArray);    }    @Test    public void testReadByte() {        for (int i = 0; i < LEN; i++) {            if (bais.available() > 0) {                int tempByte = bais.read();                System.out.printf("%d, %s, %s\n", tempByte, Integer.toBinaryString(tempByte), Integer.toBinaryString('A' + i));            }        }    }    @Test    public void testReadBytes() {        byte[] temp = new byte[LEN];        int len = bais.read(temp, 0, LEN);        System.out.println("Total read " + len + " bytes");        System.out.println("The result is: " + Arrays.toString(temp));        System.out.println("The original array is: " + Arrays.toString(byteArray));    }    @Test    public void testSkip() {        int temp1 = bais.read();        System.out.println("The byte is: " + temp1);        Long skipNum = bais.skip(2); // 跳过2个字节        int temp2 = bais.read();        System.out.println("After skipping 2 bytes\nThe byte is: " + temp2);    }    @Test    public void testAvailable() {        int availableNum = bais.available();        System.out.println("Before reading, there are " + availableNum + " bytes available");        int temp = bais.read();        availableNum = bais.available();        System.out.printf("After reading %d, there are %d bytes available.\n", temp, availableNum);    }    @Test    public void testMarkAndReset() {        boolean isSupported = bais.markSupported();        System.out.println("mark() method is " + (isSupported ? "supported" : "not supported"));        if (isSupported) {            //标记当前位置,即byteArray[0]            bais.mark(99999);//mark(readAheadLimit)中的readAheadLimit目前没有实际意义            int temp = bais.read(); //65 byteArray[0]            temp = bais.read(); //66 byteArray[1]            System.out.println("The next byte is " + bais.read());//should be 67 byteArray[2]            //重置字节数组输入流的读取位置为最后一次mark标记的位置            bais.reset();            System.out.println("After resetting, the next byte is " + bais.read());//65 byteArray[0]        }    }}
  1. ByteArrayOutputStream实例 (测试基于 junit-4.12)
package test.io;import org.junit.Before;import org.junit.Test;import java.io.ByteArrayOutputStream;import java.io.IOException;public class ByteArrayOutputStreamTest {    private static final int LEN = 6;    private static final byte[] byteArray = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};    private ByteArrayOutputStream baos;    @Before    public void beforeTest() {        //创建一个字节数组输出流        baos = new ByteArrayOutputStream();    }    @Test    public void testWriteByte() {        baos.write(byteArray[0]);//写入一个字节:A        baos.write(byteArray[1]);        baos.write(byteArray[2]);        baos.write(byteArray[3]);        baos.write(byteArray[4]);        System.out.println("baos=" + baos);    }    @Test    public void testWriteBytes() {        baos.write(byteArray, 0, 5); //写入一组字节,从下标为0处开始,写入长度为5    }    @Test    public void testSize() {        baos.write(byteArray[0]);        baos.write(byteArray[1]);        baos.write(byteArray[2]);        System.out.println("The size of baos is: " + baos.size());    }    @Test    public void testWriteTo() {        baos.write(byteArray[0]);        baos.write(byteArray[1]);        baos.write(byteArray[2]);        //将baos写入到另外一个输出流中        ByteArrayOutputStream baos1 = new ByteArrayOutputStream();        try {            baos.writeTo(baos1);            System.out.println("baos1=" + baos1);        } catch (IOException e) {            e.printStackTrace();        }    }    @Test    public void testToArray() {        baos.write(byteArray[0]);        baos.write(byteArray[1]);        baos.write(byteArray[2]);        byte[] temp = baos.toByteArray();        System.out.println("The contents is: "+ new String(temp));    }}
0 0