Java 日看一类(48)之IO包中的PushbackInputStream

本文详细介绍了PushbackInputStream类的功能及其实现原理。此类为输入流添加了回推和取消读取一个字节的能力,适用于需要读取由特定分隔符分隔的不确定大小的数据场景。文章还介绍了该类的主要成员变量和方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该类继承自FilterInputStream

没有引入包




该类的类头注释如下:

/**
 * A <code>PushbackInputStream</code> adds
 * functionality to another input stream, namely
 * the  ability to "push back" or "unread"
 * one byte. This is useful in situations where
 * it is  convenient for a fragment of code
 * to read an indefinite number of data bytes
 * that  are delimited by a particular byte
 * value; after reading the terminating byte,
 * the  code fragment can "unread" it, so that
 * the next read operation on the input stream
 * will reread the byte that was pushed back.
 * For example, bytes representing the  characters
 * constituting an identifier might be terminated
 * by a byte representing an  operator character;
 * a method whose job is to read just an identifier
 * can read until it  sees the operator and
 * then push the operator back to be re-read.
 *
 * @author  David Connelly
 * @author  Jonathan Payne
 * @since   JDK1.0
 */

大意如下:

PushbackInputStream为其他输入流添加了新功能,该功能提供了回推和取消读取一个字节的能力

在片段代码需要读取由特定分隔符分隔的不确定大小的数据时是很方便和有用的

在读到终止字符后,该代码片段可以取消读取该字符,因此下一个read操作将会重复读取被回推的该byte

例如,表示构成标识符字符的字节可能由表示操作符字符的字节终止;用于读取一个标识符的方法可以读取到遇到操作符为止,然后将该操作符推回以进行重读



该类含有如下的成员变量:

读取缓冲区

protected byte[] buf;

读取标志位:

protected int pos;




该类含有如下的成员方法:

检测流有效状态

private void ensureOpen() throws IOException {
    if (in == null)
        throw new IOException("Stream closed");
}

构造函数(给予输入流和缓冲区大小

public PushbackInputStream(InputStream in, int size) {
    super(in);
    if (size <= 0) {
        throw new IllegalArgumentException("size <= 0");
    }
    this.buf = new byte[size];
    this.pos = size;
}

构造函数(默认缓冲区大小为1

public PushbackInputStream(InputStream in) {
    this(in, 1);
}

读取方法(读出一个字节数据

public int read() throws IOException {
    ensureOpen();
    if (pos < buf.length) {//当前缓冲区不为空
        return buf[pos++] & 0xff;
    }
    return super.read();//缓冲区为空直接从流中读取
}

读取方法(读出数组数据

public int read(byte[] b, int off, int len) throws IOException {
    ensureOpen();
    if (b == null) {
        throw new NullPointerException();
    } else if (off < 0 || len < 0 || len > b.length - off) {
        throw new IndexOutOfBoundsException();
    } else if (len == 0) {
        return 0;
    }

    int avail = buf.length - pos;//缓冲区剩余数据
    if (avail > 0) {//缓冲区不为空
        if (len < avail) {//需要读取长度小于剩余长度
            avail = len;
        }
        System.arraycopy(buf, pos, b, off, avail);
        pos += avail;//修改读取指针
        off += avail;//修改数组偏移量
        len -= avail;//修改剩余需读取长度
    }
    if (len > 0) {
        len = super.read(b, off, len);//直接从流中读取剩余数据
        if (len == -1) {//流已关闭,数据发送完毕
            return avail == 0 ? -1 : avail;
        }
        return avail + len;
    }
    return avail;//返回实际读取长度
}

推回字节数据(推回到缓冲区

public void unread(int b) throws IOException {
    ensureOpen();
    if (pos == 0) {//无法推回,缓冲区已满
        throw new IOException("Push back buffer is full");
    }
    buf[--pos] = (byte)b;
}

推回字节数据(推回一个数组

public void unread(byte[] b, int off, int len) throws IOException {
    ensureOpen();
    if (len > pos) {//缓冲区无用空间小于推回长度
        throw new IOException("Push back buffer is full");
    }
    pos -= len;
    System.arraycopy(b, off, buf, pos, len);
}

推回数组

public void unread(byte[] b) throws IOException {
    unread(b, 0, b.length);
}

返回可无阻塞读取的数据量

public int available() throws IOException {
    ensureOpen();
    int n = buf.length - pos;
    int avail = super.available();
    return n > (Integer.MAX_VALUE - avail)//返回缓冲区有效值与流中有效值的和和int最大值中较小的值
                ? Integer.MAX_VALUE
                : n + avail;
}

跳过后续的字节

public long skip(long n) throws IOException {
    ensureOpen();
    if (n <= 0) {
        return 0;
    }

    long pskip = buf.length - pos;//缓冲区可跳过的数据值
    if (pskip > 0) {
        if (n < pskip) {//可直接跳过
            pskip = n;
        }
        pos += pskip;//修改缓冲区偏移量
        n -= pskip;//修改剩余需跳过数据
    }
    if (n > 0) {
        pskip += super.skip(n);//直接从流中跳过剩余数据
    }
    return pskip;//返回实际需要跳过的值
}

是否支持标记回滚操作(不支持

public boolean markSupported() {
    return false;
}

标记操作(当然为空

public synchronized void mark(int readlimit) {
}

回滚操作(当然也为空

public synchronized void reset() throws IOException {
    throw new IOException("mark/reset not supported");
}

关闭流

public synchronized void close() throws IOException {
    if (in == null)
        return;
    in.close();//内嵌的输入流关闭
    in = null;
    buf = null;//缓冲区释放
}



该类的推回操作蛮有意思的,以前并没有使用过该类,对该操作不是很熟悉。不过该操作相当于对流数据进行了分隔,对输出的数据进行了分离和加工。同时需要注意该类的缓冲区储存的并不是从流中读取出的数据,而是推回的数据,所以缓冲区的设置应该大于你想推回的最大数据值(尽量不要使用默认构造函数,请自己指定缓冲区大小)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值