java.io包里的类太多了,第一次看到这些API时会感觉非常零乱,实际上是因为里面用了装饰者模式(设计模式中写),会一层层包装扩展,因此类会很多,显得很琐碎。里面的绝大部分类图如下,图片来自:http://davidisok.iteye.com/blog/2106489
java中读取文件内容或者写入文件内容都是以流的形式来操作,流可以想象成一个"管道",“管道”的两端分别连接着文件和程序,如下:
java中io流按照数据流的方向不同可分为输入流、输出流。按照处理数据单位的不同可分为字节流和字符流(字节流一次处理一个字节,字符流一次处理两个字节)。并且所有的流分别继承以下四种抽象流类型:
如果io流按照功能的不同还可以分为节点流和处理流。节点流是可以直接从一个特定的数据源(节点)读写数据。
处理流是连接在已存在的流(节点流和处理流)之上,通过对数据的处理为程序提供更为强大的功能。说白了,处理流就是在原来的节点流或者处理流上进行一层包装、扩展(装饰者),提供更为强大的功能。
InputStream、OutputStream、Reader、Writer源码如下:
public abstract class InputStream implements Closeable {//字节输入流的所有类的超类 JDK1.7 java.util
private static final int MAX_SKIP_BUFFER_SIZE = 2048;//最多能跳过的字节数
public abstract int read() throws IOException;//从输入流中读取数据的下一个字节。即一根管道连着文件,从文件中读取一个字节给程序
public int read(byte b[]) throws IOException {//从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
return read(b, 0, b.length);
}
//将输入流中最多 len个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值
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();//off表示数组中写入数据的初始偏移量,参数进行校验
} else if (len == 0) {
return 0;//此时不读入数据
}
int c = read();//读取一个字节
if (c == -1) {//-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;
}
public long skip(long n) throws IOException {//跳过和丢弃此输入流中数据的 n个字节
long remaining = n;
int nr;
if (n <= 0) {
return 0;
}
int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);//获取较小值
byte[] skipBuffer = new byte[size];
while (remaining > 0) {
nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
if (nr < 0) {
break;
}
remaining -= nr;
}
return n - remaining;
}
public int available() throws IOException {
return 0;
}
public void close() throws IOException {}//关闭此输入流并释放与该流关联的所有系统资源。即直接关闭管道
public synchronized void mark(int readlimit) {}//在此输入流中标记当前的位置
public synchronized void reset() throws IOException {//将此流重新定位到最后一次对此输入流调用 mark方法时的位置
throw new IOException("mark/reset not supported");
}
public boolean markSupported() {//测试此输入流是否支持 mark 和 reset方法
return false;
}
}
public abstract class OutputStream implements Closeable, Flushable {//字节输出流的所有类的超类
public abstract void write(int b) throws IOException;//将指定的字节写入此输出流。写入参数 b的八个低位。b的 24个高位将被忽略
public void write(byte b[]) throws IOException {//将 b.length个字节从指定的 byte数组写入此输出流
write(b, 0, b.length);
}
//将指定 byte 数组中从偏移量 off开始的 len个字节写入此输出流
public void write(byte b[], int off, int len) throws IOException {
if (b == null) {
throw new NullPointerException();//字节不能为null
} else if ((off < 0) || (off > b.length) || (len < 0) ||
((off + len) > b.length) || ((off + len) < 0)) {//参数校验
throw new IndexOutOfBoundsException();
} else if (len == 0) {//写入长度为0直接返回
return;
}
for (int i = 0 ; i < len ; i++) {
write(b[off + i]);//写入字节
}
}
public void flush() throws IOException {//刷新此输出流并强制写出所有缓冲的输出字节
}
//关闭此输出流并释放与此流有关的所有系统资源。即直接关闭管道。应先调用flush刷新缓冲区再关闭
public void close() throws IOException {
}
}
public abstract class Reader implements Readable, Closeable {//用于读取字符流的抽象类
protected Object lock;//用于同步针对此流的操作的对象
protected Reader() {
this.lock = this;//创建一个新的字符流 reader
}
protected Reader(Object lock) {//创建一个新的字符流 reader
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
public int read(java.nio.CharBuffer target) throws IOException {//试图将字符读入指定的字符缓冲区。cbuf - 目标缓冲区
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];
}
public int read(char cbuf[]) throws IOException {//将字符读入数组
return read(cbuf, 0, cbuf.length);
}
abstract public int read(char cbuf[], int off, int len) throws IOException;
private static final int maxSkipBufferSize = 8192;
private char skipBuffer[] = null;
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() {//判断此流是否支持 mark()操作
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;//关闭该流并释放与之关联的所有资源。即直接关闭管道
}
public abstract class Writer implements Appendable, Closeable, Flushable {//写入字符流的抽象类
private char[] writeBuffer;//
private final int writeBufferSize = 1024;
protected Object lock;//用于同步针对此流的操作的对象。
protected Writer() {//创建一个新的字符流 writer
this.lock = this;
}
protected Writer(Object lock) {//创建一个新的字符流 writer
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
public void write(int c) throws IOException {//写入单个字符。要写入的字符包含在给定整数值的 16个低位中,16高位被忽略
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[writeBufferSize];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
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 {//将指定字符序列添加到此 writer
if (csq == null)
write("null");
else
write(csq.toString());
return this;
}
//将指定字符序列的子序列添加到此 writer.Appendable。
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;
}
//将指定字符添加到此 writer
public Writer append(char c) throws IOException {
write(c);
return this;
}
abstract public void flush() throws IOException;//刷新该流的缓冲
abstract public void close() throws IOException;//关闭此流,但记得要先刷新它
}