JDK源码:ByteArrayInputStream

Posted jdkSpring

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK源码:ByteArrayInputStream相关的知识,希望对你有一定的参考价值。

       ByteArrayInputStream 是字节数组输入流。它继承于InputStream。

       它包含一个内部缓冲区,该缓冲区包含从流中读取的字节,它的内部缓冲区就是一个字节数组,而ByteArrayInputStream本质就是通过字节数组来实现的。

       我们都知道,InputStream通过read()向外提供接口,供它们来读取字节数据;而ByteArrayInputStream 的内部额外的定义了一个计数器,它被用来跟踪 read() 方法要读取的下一个字节。

类名

public class ByteArrayInputStream extends InputStream 

成员变量                          

/**  * 字节数组缓冲区。 * 元素buf[0]到buf[count-1]是唯一可以从流中读取的字节 * 元素buf[pos]是下一个要读取的字节 */protected byte buf[];/** * 从输入流缓冲区读取的下一个字符的索引。 * 此值应始终为非负且不大于count的值。 * 从输入流缓冲区读取的下一个字节将是buf[pos]。 */protected int pos;/** * 流中当前标记的位置。 * 在构造时,默认情况下,ByteArrayInputStream对象标记在位置0处。 * 它们可以用mark()方法标记在缓冲区内的另一个位置。 * 当前缓冲区位置由reset()方法设置到这一点。 * 如果未设置标记,则标记的值是传递给构造函数的偏移量(如果未提供偏移量,则为0). */protected int mark = 0;/** * 一个大于输入流缓冲区中最后一个有效字符的索引。* 此值应始终为非负且不大于buf的长度。* 它比输入流缓冲区中最后一个字节的位置大一个 */protected int count;

方法

/** * 创建ByteArrayInputStream,使用buf作为缓冲区数组。 * pos的初始值是0,count的初始值是buf的长度 */public ByteArrayInputStream(byte buf[])/** * @param buf 目标字节数组 * @param offset 要读取的第一个字节的缓冲区中的偏移量. * @param length 从缓冲区读取的最大字节数。 */public ByteArrayInputStream(byte buf[], int offset, int length)/** * 从这个输入流中读取下一个字节的数据。 * 在0到255的范围内,返回值字节作为int型返回。 * 如果到达流的末尾而没有字节可用,则返回-1。 */public synchronized int read()/** * 从这个输入流将数据的字节读入一个字节数组。 * 如果pos等于count,则返回-1表示文件结束。 * 否则,读取的字节数avail等于len和count-pos中的较小者。 * 如果avail为正,则字节buf[pos]到buf[pos+avail-1]被复制到b[off]到b[off+avail-1]中, * pos的值修改为pos+avail,并返回avail。 * @param b 目标字节数组. * @param off 目标数组b中的起始偏移量 * @param len 读取的最大字节数. * @return 读取到缓冲区中的字节总数, * 如果由于已到达流的结尾而没有更多数据,则为-1。 */public synchronized int read(byte b[], int off, int len)/** * 跳过n个字符 */public synchronized long skip(long n)/** * 返回可从此输入流读取(或跳过)的剩余字节数。 */public synchronized int available()//此方法只有一行代码:return truepublic boolean markSupported()/** * 设置流中当前标记的位置。 * 在构造时,默认情况下, * ByteArrayInputStream对象标记在位置0处。 * 可以用这种方法标记在缓冲区内的另一个位置 */public void mark(int readAheadLimit)/** * 将缓冲区重置到标记位置。 * 除非在构造函数中标记了另一个位置或指定了偏移量, * 否则标记位置为0 */public synchronized void reset()/** * ByteArrayInputStream是基于内存Byte数组的流, * 不需要close,当没有强引用的时候会自动被垃圾回收了, * 所以close实现为空。 */public void close() throws IOException

read()

/** * 从这个输入流中读取下一个字节的数据。* 在0到255的范围内,返回值字节作为int型返回。* 如果到达流的末尾而没有字节可用,则返回-1。 */public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1;}

read(byte b[], int off, int len)

/** * 从这个输入流将数据的字节读入一个字节数组。 * 如果pos等于count,则返回-1表示文件结束。 * 否则,读取的字节数avail等于len和count-pos中的较小者。 * 如果avail为正,则字节buf[pos]到buf[pos+avail-1]被复制到b[off]到b[off+avail-1]中, * pos的值修改为pos+avail,并返回avail。 * @param b 目标字节数组. * @param off 目标数组b中的起始偏移量 * @param len 读取的最大字节数. * @return 读取到缓冲区中的字节总数, * 如果由于已到达流的结尾而没有更多数据,则为-1。 */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;}

skip(long n)

/** * 跳过n个字符,k为实际跳过的字节 */public synchronized long skip(long n) { long k = count - pos; if (n < k) { k = n < 0 ? 0 : n; }    pos += k; return k;}

available()

/** * 返回可从此输入流读取(或跳过)的剩余字节数。 */public synchronized int available() { return count - pos;}

mark(int readAheadLimit)

/*** 设置流中当前标记的位置。* 在构造时,默认情况下,* ByteArrayInputStream对象标记在位置0处。* 可以用这种方法标记在缓冲区内的另一个位置*/public void mark(int readAheadLimit) { mark = pos;}

reset()

/*** 将缓冲区重置到标记位置。* 除非在构造函数中标记了另一个位置或指定了偏移量,* 否则标记位置为0*/public synchronized void reset() { pos = mark;}

代码注释

public class ByteArrayInputStream extends InputStream {    /** * 字节数组缓冲区。 * 元素buf[0]到buf[count-1]是唯一可以从流中读取的字节 * 元素buf[pos]是下一个要读取的字节 */ protected byte buf[];    /** * 从输入流缓冲区读取的下一个字符的索引。 * 此值应始终为非负且不大于count的值。 * 从输入流缓冲区读取的下一个字节将是buf[pos]。 */ protected int pos;    /** * 流中当前标记的位置。 * 在构造时,默认情况下,ByteArrayInputStream对象标记在位置0处。 * 它们可以用mark()方法标记在缓冲区内的另一个位置。 * 当前缓冲区位置由reset()方法设置到这一点。 * 如果未设置标记,则标记的值是传递给构造函数的偏移量(如果未提供偏移量,则为0). * * @since JDK1.1 */ protected int mark = 0;    /** * 一个大于输入流缓冲区中最后一个有效字符的索引。 * 此值应始终为非负且不大于buf的长度。 * 它比输入流缓冲区中最后一个字节的位置大一个 */ protected int count;    /** * 创建ByteArrayInputStream,使用buf作为缓冲区数组。 * pos的初始值是0,count的初始值是buf的长度 */ public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; this.count = buf.length; }    /** * @param buf 目标字节数组 * @param offset 要读取的第一个字节的缓冲区中的偏移量. * @param length 从缓冲区读取的最大字节数。 */ public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf; this.pos = offset; this.count = Math.min(offset + length, buf.length); this.mark = offset; }    /** * 从这个输入流中读取下一个字节的数据。 * 在0到255的范围内,返回值字节作为int型返回。 * 如果到达流的末尾而没有字节可用,则返回-1。 */ public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; }    /** * 从这个输入流将数据的字节读入一个字节数组。 * 如果pos等于count,则返回-1表示文件结束。 * 否则,读取的字节数avail等于len和count-pos中的较小者。 * 如果avail为正,则字节buf[pos]到buf[pos+avail-1]被复制到b[off]到b[off+avail-1]中, * pos的值修改为pos+avail,并返回avail。 * @param b 目标字节数组. * @param off 目标数组b中的起始偏移量 * @param len 读取的最大字节数. * @return 读取到缓冲区中的字节总数, * 如果由于已到达流的结尾而没有更多数据,则为-1。 */ 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; }    public boolean markSupported() { return true; }    /** * 设置流中当前标记的位置。 * 在构造时,默认情况下, * ByteArrayInputStream对象标记在位置0处。 * 可以用这种方法标记在缓冲区内的另一个位置 */ public void mark(int readAheadLimit) { mark = pos; }    /** * 将缓冲区重置到标记位置。 * 除非在构造函数中标记了另一个位置或指定了偏移量, * 否则标记位置为0 */ public synchronized void reset() { pos = mark; }    /** * ByteArrayInputStream是基于内存Byte数组的流, * 不需要close,当没有强引用的时候会自动被垃圾回收了, * 所以close实现为空。 */ public void close() throws IOException { }
}

案例

public class ByteArrayInputStreamDemo {    public static void main(String[] args) { ByteArrayInputStream bais=null; StringBuilder sb=new StringBuilder(); int temp=0; int num=0; long date1=System.currentTimeMillis(); try{ byte[] b="abcdefghijklmnopqstuvxyz".getBytes(); //从字符数组b中读取数据,从下标为2开始计数读8个 bais=new ByteArrayInputStream(b,2,8); while((temp=bais.read())!=-1){ sb.append((char)temp); num++; } System.out.println(sb); System.out.println("读取的字节数:"+num); }finally{ try{ bais.close();//不需要关闭流的,但是调用close没有任何影响,close不做任何事情 }catch(IOException e){ e.printStackTrace(); } } long date2=System.currentTimeMillis(); System.out.println("耗时:"+(date2-date1)); }}


以上是关于JDK源码:ByteArrayInputStream的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8源码下载及idea2021导入jdk1.8源码

关于JDK源码:我想聊聊如何更高效地阅读

关于JDK源码:我想聊聊如何更高效地阅读

idea 导入 jdk源码 解决compile code 后阅读jdk 源码

关于JDK源码:我想聊聊如何更高效地阅读.md

怎样读jdk源码