Java8 I/O源码-ByteArrayInputStream

来源:互联网 发布:java小项目开发实例 编辑:程序博客网 时间:2024/05/18 12:02

前两篇文章Java8 I/O源码-InputStream和Java8 I/O源码-OutputStream简单介绍了IntputStream和OutputStream。本文将详细介绍ByteArrayInputStream的实现,拉开学习字节型输入流的序幕。

ByteArrayInputStream属于字节型输入流,包含一个内部缓冲区,该缓冲区包含从流中读取的字节。定义如下:

public class ByteArrayInputStream extends InputStream

outline

字段
字段 说明 protected byte buf[] 用来创建流的字节数组。 protected int pos 从输入流缓冲器中读取的下个字节的索引。 protected int mark = 0 流中的当前标记位置。 protected int count 字节流的长度
构造方法
方法 说明 public ByteArrayInputStream(byte buf[]) {…} 创建一个ByteArrayInputStream,使用buf作为其缓冲区数组。 public ByteArrayInputStream(byte buf[], int offset, int length) {…} 创建一个ByteArrayInputStream,使用buf作为其缓冲区数组,并指定标记位置和可以从缓冲区中可以读取字节的最大长度。
方法
方法 说明 public synchronized int read() {…} 从此输入流中读取下一个数据字节。 public synchronized int read(byte b[], int off, int len) {…} 将最多len个数据字节从此输入流读入byte数组。 public synchronized long skip(long n) {…} 从此输入流中跳过n个输入字节。 public synchronized int available() {…} 返回可从此输入流读取(或跳过)的剩余字节数。 public boolean markSupported() {…} 测试是否支持 mark/reset。 public void mark(int readAheadLimit) {…} 设置流中的当前标记位置。 public synchronized void reset() {…} 将缓冲区的位置重置为标记位置。 public void close() throws IOException {…} 关闭ByteArrayInputStream,此方法无效。

构造方法

ByteArrayInputStream( byte buf[])
/** * 创建一个ByteArrayInputStream,使用buf作为它的缓冲区数组。 *  * pos的初始值为0。 * count的初始值为buf的长度。 * * @param   buf   作为输入缓存区的字节数组。 */public ByteArrayInputStream(byte buf[]) {    // 使用buf作为缓冲区数组。    this.buf = buf;    // pos的初始值为0。    this.pos = 0;    // count的初始值为buf的长度。    this.count = buf.length;}
ByteArrayInputStream( byte buf[], int offset, int length)
/** * 创建一个ByteArrayInputStream,使用buf作为它的缓冲区数组。 * pos的初始值为offset。 * count的初始值为offset+length和buf.length的最小值。 * 将mark的值设为offset。 * * @param   buf      作为输入缓存区的字节数组。 * @param   offset   缓冲区要读取的第一个字节的偏移量。 * @param   length   可以从缓冲区中读取的最大字节数。 */public ByteArrayInputStream(byte buf[], int offset, int length) {    this.buf = buf;    this.pos = offset;    //count的初始值为offset+length和buf.length的最小值    this.count = Math.min(offset + length, buf.length);    this.mark = offset;}

方法

read()
/** * 从此输入流中读取下一个数据字节。 * 返回一个 0 到 255 范围内的 int 字节值。 * 如果因为到达流末尾而没有可用的字节,则返回值-1。 *  * 此read方法不会阻塞。 * * @return  the next byte of data, or <code>-1</code> if the end of the *          stream has been reached. */public synchronized int read() {    // 如果pos < count为false,说明到达流末尾,这时没有可用的字节,返回-1;如果为true,此输入流中读取下一个数据字节。    return (pos < count) ? (buf[pos++] & 0xff) : -1;}
read( byte b[], int off, int len)
/** * 从输入流中,读取最多len个字节到字节数组中。 *  * 如果pos大于等于count,则代表到达文件末尾,返回-1指示文件结束。 *  * 否则,读取的字节数k等于len和count-pos中的较小者。 * 如果k是正数,则以System.arraycopy执行的方式将buf[pos]到buf[pos+k-1]的字节复制到b[off]到b[off+k-1]中。 * 将值k与pos相加并返回k。 * * 此read方法不会阻塞。 * * @param   b     存储读入数据的缓冲区。 * @param   off   起始偏移量 * @param   len   读取的最大字节数。 * @return  读入缓冲区的总字节数,如果由于已到达流末尾而不再有数据,则返回-1。 * @exception  NullPointerException 如果b为null。 * @exception  IndexOutOfBoundsException 如果off为负,len为负,或者len大于b.length - 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();    }    // 如果pos大于等于count,则代表到达文件末尾,返回-1指示文件结束。    if (pos >= count) {        return -1;    }    // 计算可以的字节数    int avail = count - pos;    // 重新计算读取的最大字节数    if (len > avail) {        len = avail;    }    //如果读取的最大字节数小于等于0,返回0    if (len <= 0) {        return 0;    }    // 从输入流中,读取len个字节到字节数组中。    System.arraycopy(buf, pos, b, off, len);    // pos后移n个位置    pos += len;    //读入缓冲区的总字节数    return len;}
skip( long n)
/** * 从输入流中跳过n个输入字节。 *  * 如果已到达输入流末尾,则可能会跳过较少的字节。 * 实际跳过的字节数k等于n和count-pos中的较小者。 * 将值k与pos相加并返回k。 * * @param   n   要跳过的字节数。 * @return  实际跳过的字节数。 */public synchronized long skip(long n) {    // 计算可以跳过的最大字节数    long k = count - pos;    //计算实际可以跳过的字节数    if (n < k) {        k = n < 0 ? 0 : n;    }    // 跳过k个字节。    pos += k;    //返回实际跳过的字节。    return k;}
available()
/** * 返回可从此输入流读取(或跳过)的剩余字节数。 *  * 返回值是 count - pos,不受阻塞地从此输入流读取(或跳过)的剩余字节数。 * * @return  不受阻塞地从此输入流读取(或跳过)的剩余字节数 */public synchronized int available() {    return count - pos;}
markSupported()
/** * 测试此 InputStream 是否支持 mark/reset。  * ByteArrayInputStream 支持 mark/reset。 * * @since   JDK1.1 */public boolean markSupported() {    return true;}
mark( int readAheadLimit)
/** * 设置流中的当前标记位置。 *  * 构造时默认将 ByteArrayInputStream 对象标记在位置零处。通过此方法可将其标记在缓冲区内的另一个位置处。 *  * 如果尚未设置标记,则标记值是传递给构造方法的偏移量(如果未提供偏移量,则标记值为 0)。 *  * readAheadLimit 对于此类没有意义。 * * @since   JDK1.1 */public void mark(int readAheadLimit) {    mark = pos;}
reset()
/** * 将缓冲区的位置重置为标记位置。 *  * 除非已标记了另一个位置,或者在构造方法中指定了一个偏移量,否则该标记位置是 0。 */public synchronized void reset() {    pos = mark;}
close()
/** * 关闭ByteArrayInputStream。 *  * 关闭方法无效。此类中的方法在关闭此流后仍可被调用,而不会产生任何 IOException。 */public void close() throws IOException {}

demo

import java.io.ByteArrayInputStream;import org.junit.Test;public class ByteArrayInputStreamTest {    byte[] buf = new byte[] { 2, 15, 67, -1, -9, 9 };    // 构造方法和read()    // 15,67,255,247,    // ********************    // 2,15,67,255,247,9,    @Test    public void test1() {        ByteArrayInputStream bais = new ByteArrayInputStream(buf, 1, 4);        int b;        while ((b = bais.read()) != -1) {            System.out.print(b + ",");        }        System.out.println("\n********************");        bais = new ByteArrayInputStream(buf);        while ((b = bais.read()) != -1) {            System.out.print(b + ",");        }    }    // skip()    // 15,67,255,247,9,    @Test    public void test2() {        ByteArrayInputStream bais = new ByteArrayInputStream(buf);        int b;        bais.skip(1);        while ((b = bais.read()) != -1) {            System.out.print(b + ",");        }    }    // available()    // 5,4,3,2,1,0,    @Test    public void test3() {        ByteArrayInputStream bais = new ByteArrayInputStream(buf);        while (bais.read() != -1) {            System.out.print(bais.available() + ",");        }    }    // markSupported()    // true    // 2    // 2    // ******************    // 15    @Test    public void test4() {        // 2, 15, 67, -1, -9, 9        // 默认标记值为0        ByteArrayInputStream bais = new ByteArrayInputStream(buf);        System.out.println(bais.markSupported());        System.out.println(bais.read());        bais.reset();        System.out.println(bais.read());        System.out.println("******************");        // mark()的参数没有意义        bais.mark(4);        while (bais.read() != -1) {        }        bais.reset();        System.out.println(bais.read());    }}

总结

  • 字节输入流必须提供返回下一个输入字节的read()方法。因为所有字节输入流的父类InputStream有这样一个抽象方法:public abstract int read()。
  • ByteArrayInputStream 支持 mark/reset。
  • ByteArrayInputStream的close方法无效,无法关闭此输入流。

想了解更多内容请参考

  • Java8 I/O源码系列专栏-目录

(全文完)

版权声明 作者:潘威威

原文地址:CSDN博客-潘威威的博客-http://blog.csdn.net/panweiwei1994/article/details/78145143

本文版权归作者所有,欢迎转载,但转载时请在文章明显位置给出原文作者名字(潘威威)及原文链接。请勿将本文用于任何商业用途。
原创粉丝点击