Java源码学习--InputStream、OutputStream、Reader、Writer
Java中的集合类就先告一段落了,之后会学习一下Java中的IO类的源代码。由于Java中IO类都是InputStream、OutputStream、Reader、Writer的实现类,所以这里先来看看这四个类的源代码。
一、InputStream类
该类实现了Closeable几口,不过并没有实现close()方法
InputStream需要认真查看的似乎只有read()、read(byte b[])、read(byte b[], int off, int len)三个方法
1. read()方法
关于该方法,InputStream中规定,该方法返回数据源中下一个字节的int表示,当到达末尾的时候返回-1。
在InputStream中该方法是一个抽象方法,等待着子类去实现。
2. read(byte b[], int off, int len)方法
这里跳过read(byte b[])方法的原因是因为该方法的实现就是调用read(b, 0, b.length)
public int read(byte b[], int off, int len) throws IOException {
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 c = read();
if (c == -1) {
return -1;
}
b[off] = (byte)c;
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c;
}
} catch (IOException ee) {
}
return i;
}
该方法的核心就是:使用read()方法逐个字节地读取数据源中的数据,放入到参数字节数组中,直到数据源的末尾;如果返回值为-1,说明数据源中根本没有数据,否则返回读取的字节个数(一般小于等于len参数)。
二、OutputStream
该类实现了Closeable接口和Flushable接口,前者提供close()方法、后者提供flush()方法,不过OutputStream并没有实现这两个方法。
同InputStream一样,OutputStream方法值得去分析的似乎也只有write(int byte)、write(byte b[])、write(byte b[], int off, int len)
1. write(int byte)
该方法的作用是将参数写入到output stream中去,有一点需要澄清的是,参数是一个int类型,但并不是真的写入一个int类型,只会写入其低8比特位。
2. write(byte b[], int off, int len)
同InputStream一样,这里跳过write(byte b[])的原因也是其回调了write(b, 0, b.length)
该方法的作用是将参数b[]中是数据从off开始,len个写入到output stream中去。
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);
}
}
三、Reader
该类和InputStream相对应,只不过是按字符单位处理数据。
Reader实现了Readable接口和Closeable接口,前者是为了适配nio,提供了一个read(java.nio.CharBuffer target)方法。
1. 构造器
Reader较InputStream有一个很大的不同是,其提供了支持同步的lock属性:lock
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
2. read()方法
Reader中的read()方法和read(byte b[], int off, int len)方法的关系同InputStream中是相反的,read()方法是通过后者实现的,而不是同InputStream中那样,后者是调用read()方法来实现数据的读取的。
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
这样一来对像我这样的强迫症很不适应,每次读取一个数据都需要new 一个char数组来,感觉好亏啊。
3. read(byte b[], int off, int len)
上面提到,该方法的地位等同于InputStream中的read()方法,因此,Reader并没有为该方法提供方法实现,子类需要自己去实现它。
四、Writer
同样,Writer和OutputStream相对应,其实现了Closeable、Flushable两个接口。
1. 构造器
Writer有一个char数组用来缓存:char[] writeBuffer
protected Writer() {
this.lock = this;
}
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
2. write(int c)方法
该方法负责往输出流中写入一个字符的内容,同样,由于参数是一个int类型的数据,这里只会写入参数的低16比特位。
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
同样可以看到,在Writer中,write()方法是通过write(char[] c, int off, int len)实现的;可以看到在进行写入操作的时候,Writer使用了synchronized关键字,意味着同时只有一个Writer可以进行写入操作
3. write(char[] c, int off, int len)
该方法和Reader中一样,也是供子类来实现。
4. write(String s)和write(String s, int off, int len)方法
由于String的特殊性,其可以看作一个char数组,因此Writer专门为其提供了这两个方法做处理。
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 <= WRITE_BUFFER_SIZE) {
if (writeBuffer == null) {
writeBuffer = new char[WRITE_BUFFER_SIZE];
}
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);
}
}
可见,其本质还是调用的write(char[] c, int off, int len)方法,有一个疑问:这里的synchronized关键字是否是没必要的,这里有不涉及到写入操作,而write方法中本来就有synchronized关键字的啊?