Java I/O 20 - PushbackReader

  关于 java.io.PushbackReader 的部分笔记。本文演示代码段的执行环境基于JDK版本1.7

概述

  PushbackReader允许将读取到的字符内容再回退到输入流中(实际上这些内容被保存在了底层的一个缓冲区数组buf中),在调用read方法获取字符数据时会首先从缓冲区buf中获取内容,当从buf中无法得到所要求的内容时则向底层输入流获取数据。

继承关系

1
2
3
4
5
// PushbackReader
--java.lang.Object
--java.io.Reader
--java.io.FilterReader
--java.io.PushbackReader

实现接口

类名 实现接口
PushbackReader Closeable, AutoCloseable,Readable

PushbackReader

Constructor Summary

public PushbackReader(Reader in, int size)

1
2
3
4
5
6
7
8
public PushbackReader(Reader in, int size) {
super(in);
if (size <= 0) {
throw new IllegalArgumentException("size <= 0");
}
this.buf = new char[size];
this.pos = size;
}

  初始化一个PushbackReader字符流。

public PushbackReader(Reader in)

1
2
3
public PushbackReader(Reader in) {
this(in, 1);
}

  初始化一个PushbackReader字符流。

部分方法

private void ensureOpen()

1
2
3
4
private void ensureOpen() throws IOException {
if (buf == null)
throw new IOException("Stream closed");
}

  检查当前buf是否有效且是否含有内容。

public int read()

1
2
3
4
5
6
7
8
9
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
if (pos < buf.length)
return buf[pos++];
else
return super.read();
}
}

  读取一个字符的内容并返回。通过synchronized关键字可以保证多线程环境下的线程安全。如果在调用read()方法之前曾经调用过unread()方法,那么buf中就存有unread()方法中传入的内容,在调用read()方法时需要首先读取缓冲区buf中的内容,即(pos < buf.length)。反之,直接从底层输出流中获取一个字符内容并返回。

public int read(char cbuf[], int off, int len)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
try {
if (len <= 0) {
if (len < 0) {
throw new IndexOutOfBoundsException();
} else if ((off < 0) || (off > cbuf.length)) {
throw new IndexOutOfBoundsException();
}
return 0;
}
int avail = buf.length - pos;
if (avail > 0) {
if (len < avail)
avail = len;
System.arraycopy(buf, pos, cbuf, off, avail);
pos += avail;
off += avail;
len -= avail;
}
if (len > 0) {
len = super.read(cbuf, off, len);
if (len == -1) {
return (avail == 0) ? -1 : avail;
}
return avail + len;
}
return avail;
} catch (ArrayIndexOutOfBoundsException e) {
throw new IndexOutOfBoundsException();
}
}
}

  读取长度为len的内容并保存到数组b中起始位置为off的空间中。通过synchronized关键字保证了多线程环境下的线程安全。第5 ~ 12行代码完成了参数的有效性校验。

  第13行代码计算缓冲区buf的数据内容长度,如果有未读取的内容,那么将首先返回buf中的内容并保存到cbuf中。将数据保存到cbuf后更新计算pos、off、len值。如果buf中的内容未能满足len的长度要求,那么接着从底层输入流中获取数据。第23行代码依赖底层输入流将数据填充到cbuf中,计算实际读取的数据长度并返回。

public void unread(int c)

1
2
3
4
5
6
7
8
public void unread(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (pos == 0)
throw new IOException("Pushback buffer overflow");
buf[--pos] = (char) c;
}
}

  回退一个字符到回退buf中。一旦执行了该方法,下一次调用read()方法获取的第一个字符会是该方法的入参c。通过synchronized关键字保证了多线程环境下的线程安全。如果pos到达了buf头部,那么意味着缓冲区buf已经没有空间容纳新的内容,所以向上抛出异常。反之,则将入参字符c保存到回退buf中。

public void unread(char cbuf[], int off, int len)

1
2
3
4
5
6
7
8
9
10
11
12
13
public void unread(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if (len > pos)
throw new IOException("Pushback buffer overflow");
pos -= len;
System.arraycopy(cbuf, off, buf, pos, len);
}
}

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

  将字符数组cbuf中的内容回退到缓冲区buf中。一旦执行了该方法,下一次调用read()方法获取的第一个字符会是cbuf[off],依次类推。通过synchronized关键字保证了多线程环境下的线程安全。通过调用系统方法System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)将cbuf中的内容复制保存到缓冲区buf中。

public boolean ready()

1
2
3
4
5
6
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
return (pos < buf.length) || super.ready();
}
}

  通知方法调用方当前输入流是否可提供字符内容。通过synchronized关键字保证了多线程环境下的线程安全。如果缓冲区buf中尚有可读取的字符内容,或者底层输入流可以继续通过read方法提供数据,那么则认为当前输入流可以继续对外提供数据内容。

public boolean markSupported()

1
2
3
public boolean markSupported() {
return false;
}

  PushbackReader不支持标记重读操作,所以返回false。

public void mark(int readAheadLimit)

1
2
3
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark/reset not supported");
}

  PushbackReader不支持标记重读操作,所以在调用mark()方法时向上抛出异常。

public void reset()

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

  PushbackReader不支持标记重读操作,所以在调用reset()方法时向上抛出异常。

public void close()

1
2
3
4
public void close() throws IOException {
super.close();
buf = null;
}

  关闭当前输入流。首先将底层输入流关闭,接着释放缓冲区buf占用的资源。

public long skip(long n)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public long skip(long n) throws IOException {
if (n < 0L)
throw new IllegalArgumentException("skip value is negative");
synchronized (lock) {
ensureOpen();
int avail = buf.length - pos;
if (avail > 0) {
if (n <= avail) {
pos += n;
return n;
} else {
pos = buf.length;
n -= avail;
}
}
return avail + super.skip(n);
}
}

  跳过n个长度的字符内容。n不可为负数,所以若传入一个负数长度,那么则向上抛出一个非法参数异常。第6行代码计算缓冲区buf中是否有回退的字符内容以及回退字符的长度。第8 ~ 10行代码表明需要跳过的长度n小于缓冲区buf中回退字符的长度,可以直接更新pos值完成跳过操作。反之则需要跳过缓冲区buf中的所有内容,同时跳过底层输入流中的若干字符内容以完成最终操作。最后计算实际跳过的字符长度并返回。

涉及基础知识点

  1. NIL

参考文献

  1. NIL




------------- End of this article, thanks! -------------


  版权声明:本文由N.C.Lee创作和发表,采用署名(BY)-非商业性使用(NC)-相同方式共享(SA)国际许可协议进行许可,转载请注明作者及出处。
  本文作者为 N.C.Lee
  本文标题为 Java I/O 20 - PushbackReader
  本文链接为 https://marcuseddie.github.io/2018/java-PushbackReader.html