您的位置:首页 > 编程语言 > Java开发

Java IO - Reader&Writer

2016-05-25 21:17 309 查看

基本概念

Reader/Writer(字符读取流/字符写入流),是所有字符操作流的父类。

同字节流不同,它们本身是抽象类

继承关系如下:





源码分析

1.Reader

类结构图



成员变量

/*
* 用来在流上同步操作的对象。
* 为了提高效率,字符流对象可以使用其自身以外的对象来保护关键部分。
* 因此,子类应使用此字段中的对象,而不是 this 或者同步的方法。
*/
protected Object lock;

// 表示跳跃(丢弃)操作时能丢弃的最大字符数量
private static final int maxSkipBufferSize = 8192;

// 跳跃缓冲数组,用来保存跳跃操作时读取的字符内容
private char skipBuffer[] = null;


构造函数

protected Reader() {
// 将字符流对象赋于 lock,说明我们操作的不是字符流本身,而是 lock
this.lock = this;
}

protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}

this.lock = lock;
}


read 方法,这里定义了 4 种读取方式。

①② 依靠 ③ 实现。

③ 为抽象方法,留给子类实现。

④ 是字节输入流所没有的读取方式。

//① 读取单个字符
public int read() throws IOException {

char cb[] = new char[1];

//关键-->创建了只有1个字符容量的数组,然后将字符读入该字符数组。
if (read(cb, 0, 1) == -1) {

//到达 I/O 流末尾返回 -1
return -1;
} else {

//否则返回整数字符,范围为 0 到 65535 之间 (0x00-0xffff),
return cb[0];
}
}

//② 将字符读入数组,返回读取的字符数
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}

//③ 将字符读入数组的某一部分。抽象方法,留给子类实现
public abstract  int read(char cbuf[], int off, int len) throws IOException;

//④ 将字符读入指定的字符缓冲区,返回读取的字符数
public int read(java.nio.CharBuffer target) throws IOException {

//检查字符缓冲区中剩余可空闲的空间
int len = target.remaining();

char[] cbuf = new char[len];
int n = read(cbuf, 0, len);
if (n > 0){
target.put(cbuf, 0, n);
}

return n;
}


skip,跳跃操作。具体原理在 InputStream 中已介绍过了,这里不在细说。

与 InputStream 的 skip 方法不同,字符输入流的 skip 方法是同步操作,是线程安全的。

public long skip(long n) throws IOException {

if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}

//nn 表示将要创建的缓冲数组的容量大小
int nn = (int) Math.min(n, maxSkipBufferSize);

//关键 --> 与字节输入流不同,这里是同步操作
synchronized (lock) {
// 创建跳跃缓冲数组
if ((skipBuffer == null) || (skipBuffer.length < nn)) {
skipBuffer = new char[nn];
}

//表示要跳过的字符数量
long r = n;

// 将需要跳过(丢弃)的字符读取到数组
while (r > 0) {
int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
if (nc == -1) {
break;
}

//表示剩下未跳跃(丢弃)的字符
r -= nc;
}

//返回跳跃(丢弃)的字符数量
return n - r;
}
}


剩余方法

// 如果确保流的下一次读取不堵塞,则返回 true,否则返回 false,但并不表示下一次读取会堵塞
public boolean ready() throws IOException {
return false;
}

public boolean markSupported() {
return false;
}

public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark() not supported");
}

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

abstract public void close() throws IOException;


2.Writer

类结构图



成员变量

//缓冲数组,默认写入的内容会暂时保存在该字符数组里
private char[] writeBuffer;

//缓冲数组的大小,不可变
private final int writeBufferSize = 1024;

//同 Reader
protected Object lock;


构造函数

protected Writer() {
this.lock = this;
}

protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}


wirter 方法,这里定义 5 种写入方式

①② 依靠 ③ 实现。

③ 为抽象方法,留给子类实现。

④⑤ 是字节输出流所没有的读取方式。

// ①写入单个字符
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null) {
writeBuffer = new char[writeBufferSize];
}

//将字符的 int 写入缓冲数组
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}

// ②写入字符数组
public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}

// ③写入字符数组的某一部分,抽象方法
public bstract  void write(char cbuf[], int off, int len) throws IOException;

// ④写入字符串
public void write(String str) throws IOException {
write(str, 0, str.length());
}

// ⑤写入字符串的某一部分
public void write(String str, int off, int len) throws IOException {
synchronized (lock) {
char cbuf[];

//将要写入的字符串长度与缓冲数组的容量比较
if (len <= writeBufferSize) {
if (writeBuffer == null) {
writeBuffer = new char[writeBufferSize];
}
cbuf = writeBuffer;
} else {
cbuf = new char[len];
}

//String 的方法,将字符串复制到字符数组
str.getChars(off, (off + len), cbuf, 0);
write(cbuf, 0, len);
}
}


append 方法,这里定义了 3 种添加方式。

具体实现通过调用相应的 write 方法完成,并返回 Writer 对象

// 将指定字符添加到此 writer,并返回此 writer
public Writer append(char c) throws IOException {
write(c);
return this;
}

// 将指定字符序列添加到此 writer,并返回此 writer
public Writer append(CharSequence csq) throws IOException {
if (csq == null){
//字符序列为空,则添加 null 这4个字符到 writer
write("null");
}else{
write(csq.toString());
}
return this;
}

// 将指定字符序列的子序列添加到此 writer,并返回此 writer
public Writer append(CharSequence csq, int start, int end) throws IOException {
CharSequence cs = (csq == null ? "null" : csq);
write(cs.subSequence(start, end).toString());
return this;
}


剩余方法

public abstract void flush() throws IOException;

public abstract void close() throws IOException;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java io reader writer 字符流