Java_io体系之Writer、Reader简介、走进源码——12
一:Writer
1、类功能简介:
字符输出流、本身是一个抽象类、是所有字符输出流的父类、与OutputStream相同的是、定义了所有字符输出流的标准、和一些必须具有的基本方法、和简单的实现其中有三个抽象方法必须要我们去实现的是write(char[] cbuf, int off, int len)、flush()、close()、子类可以根据自己要达到的效果或者功能、重写或者添加新的方法;与OutputStream不同的是Writer有个自带的缓存字符数组writerBuffer、它不是直接将字符写入到字符输出流管道中的、而是先放在writerBuffer中、操作单位不一样、Writer换成了对字符的操作。
2、Writer API简介:
A:关键字
private char[] writeBuffer; 字符缓存数组、用于临时存放要写入字符输出流管道中的字符、
private final int writeBufferSize = 1024; 字符缓存数组的默认大小、
protected Object lock; 用于同步针对此流的操作的对象、
B:构造方法
protected Writer(); 创建一个新的字符流、其关键部分将同步writer自身
protected Writer(Object obj); 创建一个新的字符流、其关键部分将同步obj自身
C:一般方法
Writer append(char c); 将指定字符追加到Writer中
Writer append(CharSequence csq); 将指定字符序列添加到此 writer。
Writer append(CharSequence csq, int start, int end) 将指定字符序列的子序列添加到此 writer.Appendable。
abstract void close(); 关闭此流
abstract void flush(); 刷新该流的缓冲
abstract void write(char[] cbuf, int off, int len); 写入字符数组的某一部分。
void write(int c); 写入单个字符。
void write(String str); 写入字符串。
void write(String str, int off, int len); 写入字符串的某一部分。
3、源码分析
package com.chy.io.core;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
/**
*/
public abstract class Writer implements Appendable, Closeable, Flushable {
//字符缓存数组、用于临时存放要写入字符输出流管道中的字符、
private char[] writeBuffer;
//字符缓存数组的默认大小、
private final int writeBufferSize = 1024;
//用于同步针对此流的操作的对象、
protected Object lock;
//创建一个新的字符流、其关键部分将同步writer自身
protected Writer() {
this.lock = this;
}
//创建一个新的字符流、其关键部分将同步obj自身
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
/**
* 将一个字符以整数形式写入到缓存字符数组writerBuffer中
*/
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[writeBufferSize];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
/**
* 将一个字符数组写入到writerBuffer中
*/
public void write(char cbuf[]) throws IOException {
write(cbuf, 0, cbuf.length);
}
/**
* 抽象类:将一个字符数组的一部分写入到当前流的管道中。
*/
abstract public 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 { // Don't permanently allocate very large buffers.
cbuf = new char[len];
}
str.getChars(off, (off + len), cbuf, 0);
write(cbuf, 0, len);
}
}
/**
* 将一个字符有序数列追加到当前流管道中、返回当前流对象
*/
public Writer append(CharSequence csq) throws IOException {
if (csq == null)
write("null");
else
write(csq.toString());
return this;
}
/**
* 将一个字符有序数列的一部分追加到当前流管道中、返回当前流对象
*/
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 Writer append(char c) throws IOException {
write(c);
return this;
}
/**
* flush当前流、要求子类必须重写
*/
abstract public void flush() throws IOException;
/**
* 当前流、要求子类必须重写
*/
abstract public void close() throws IOException;
}
二:Reader
1、类功能简介:
用于读取字符流的抽象类。子类必须实现的方法只有 read(char[], int, int) 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
2、Reader API简介:
A:关键字
protected Object lock; 用于同步针对此流的操作的对象。
B:构造方法
protected Reader(); 创建一个新的字符流 reader,其重要部分将同步其自身的 reader。
protected Reader(Object obj); 创建一个新的字符流 reader,其重要部分将同步给定的对象。
C:一般方法
abstract void close(); 关闭此流、释放与此流有关的所有资源
boolean markSupported(); 检测此流是否支持标记
void mark(int readAheadLimit); 标记此流、与reset()结合使用
void reset(); 将流的读取位置重置到最后一次调用mark方法时的位置
boolean ready(); 检测此流是否可读
int read(java.nio.CharBuffer target); 将输入流管道中的target.length个字节读取到指定的缓存字符数组target中、返回实际存放到target中的字符数。
int read(); 读取一个字符并返回
int read(char[] cbuf); 将字符读取到cbuf中、返回实际读取到的字符数。
abstract int read(char[] cbuf, int off, int len); 抽象类:将字符读取到下标冲off开始、len个后续位置的cbuf中。
long skip(long n); 从剩余有效字符中跳过n个
3、源码分析
package com.chy.io.core;
import java.io.Closeable;
import java.io.IOException;
/**
* Reader:字符输入流、本身是抽象类、为所有字符输入流类提供一个标准、和基本方法及简单实现、与InputStream相比、多实现一个Readble接口、
* 支持将字符读取到指定的缓存字符数组中。要求子类重写read(char[] cbuf, int off, int len)、close()、这两个方法、一般子类都会重写Reader提供的方法
* 或者部分方法、也可能添加新的方法来体现自己的特色。与InputStream的本质区别就是操作单位不同、由字节变为字符。
*/
public abstract class Reader implements Readable, Closeable {
/**
* 用于同步针对此流的操作的对象。
*/
protected Object lock;
/**
* 创建一个新的字符流 reader,其重要部分将同步其自身的 reader。
*/
protected Reader() {
this.lock = this;
}
/**
* 创建一个新的字符流 reader,其重要部分将同步给定的对象。
*/
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
/**
* 将输入流管道中的target.length个字节读取到指定的缓存字符数组target中、返回实际存放到target中的字符数。
*/
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;
}
/**
* 读取一个字符并返回
*/
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
/**
* 将字符读取到cbuf中、返回实际读取到的字符数。
*/
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}
/**
* 抽象类:将字符读取到下标冲off开始、len个后续位置的cbuf中。
*/
abstract public int read(char cbuf[], int off, int len) throws IOException;
/** 最大允许跳过字符数 */
private static final int maxSkipBufferSize = 8192;
/** 用于skip方法临时存放字符 */
private char skipBuffer[] = null;
/**
* 从剩余有效字符中跳过n个
*/
public long skip(long n) throws IOException {
if (n < 0L)
throw new IllegalArgumentException("skip value is negative");
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;
}
}
/** 检测此流是否可读*/
public boolean ready() throws IOException {
return false;
}
/** 检测此流是否支持标记*/
public boolean markSupported() {
return false;
}
/** 标记此流、与reset()结合使用*/
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark() not supported");
}
/** 将流的读取位置重置到最后一次调用mark方法时的位置*/
public void reset() throws IOException {
throw new IOException("reset() not supported");
}
/** 关闭此流、释放与此流有关的所有资源*/
abstract public void close() throws IOException;
}
总结:
通过两组对比来观察一下相同与区别
OutputStream/InputStream VS Writer/Reader
相同:
都是抽象类、为所有子类提供标准、和基本的方法及简单实现、关键方法是抽象方法、要子类根据自己的特色去实现
其他读写方法都是以这个关键方法为核心实现的、Reader/InputStream都继承了closeable接口。
Writer/OutputStream都继承了Closeable,Flushable
区别:
本质区别——操作的对象不同。字节流针对的是字节、字符流针对的是字符
Reader相比与InputStream多实现了一个Readable接口、用于提供一个可以将字符写入到指定缓存数组的方法
同时两者用于实现读取的关键抽象方法、reader.read(char[] cbuf,int off, int len)、inputStream.read();
一个是针对字符数组、一个是针对单个字节、其他的读取方法都是以这两个方法为核心的。
还有一个区别就是两者的close()方法类型不一样、Reader的close方法是抽象类、必须要子类重写、
InputStream.close不是抽象类、子类可以重写、也可不重写。
Writer相比与OutputStream多实现了一个Appendable接口、用于向此流中追加字符。两者用于读取的关键方法也是一个针对字符数组、一个针对字节
并且Writer的close()、flush()方法都是抽象类、必须要子类实现具有自己的特色。