Java IO
Java的输入输出流,用于和程序外部交换数据。Java的IO是通过流式传输的
流的链接机制
可将一个流和另一个流首尾相接,以将输入数据转换成相应的输出数据
IO流接口
流 | 对应抽象类 |
---|---|
输入流 | InputStream/Reader |
输出流 | OutputStream/Writer |
字节流 | InputStream/OutputStream |
字符流 | Reader/Writer |
InputStream
字节输入流,以字节为单位从程序外部获取数据
类型 | 作用 | API |
---|---|---|
统计 | 流内有效字节数 | available() |
读 | 读出一个字节 | read() |
读出一定长度字节 | read(byte[],int offset,lenght) | |
跳过 | 跳过一定长度字节开始读 | skip(long n) |
回溯 | 能否标记 | markSupported |
标记当前读的位置 | mark(int readlimit) | |
回到标记开始读 | reset | |
关闭 | 清空缓冲区 | flush() |
关闭流 | close() |
真是令人望而生畏!
节选了几个重要输入流实现类
从类图可以清楚地看到,左边三个实现类有InputStream的引用,意味着他们内部有流的链接。而右侧几个实现类则最多只能链接同类型的输入流
实现类 | 描述 |
---|---|
ObjectInputSteam | 从其他InputStream中读出Object |
SequenceInputStream | 持有一组InputStream,读完一个换一个 |
FilterInputStream | 从其他InputStream过滤输入数据并读出 |
StringInptStream | 从字符串或其他String输入流中读出字节数据 |
ByteArrayInputStream | 从字节数组中读出字节数据 |
PipedInputStream | |
FileInputStream | 从文件中读字节数据 |
实现类源码解析
简略解析,其中ObjectInputStream和PipedInputStream由于篇幅较长,以后再解析
ByteArrayInputStream
从字节数组中读出字节数据
成员变量 | 含义 |
---|---|
byte buf[] | 流的数据缓冲 |
int pos | 当前读的位置 |
int mark = 0 | 标记的位置 |
int count | 缓冲长度 |
//构造函数提供字节数组源,直接复制到流的缓冲区,初始化下一次读的位置以及缓冲区大小
public ByteArrayInputStream(byte buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
//缓冲无可用数据返回-1,有就读一个字节放在int的后8位返回并更新下一次读的位置
public synchronized int read() {
return (pos < count) ? (buf[pos++] & 0xff) : -1;
}
//缓冲无可用数据返回-1,否则复制到参数提供的数组中,返回实际复制的字节数
public synchronized int read(byte b[], int off, int len) {
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
}
if (pos >= count) {
return -1;
}
int avail = count - pos;
if (len > avail) {
len = avail;
}
if (len <= 0) {
return 0;
}
System.arraycopy(buf, pos, b, off, len);
pos += len;
return len;
}
//下次读的位置+n,如果超过缓冲区尾部则设为缓冲区尾部
public synchronized long skip(long n) {
long k = count - pos;
if (n < k) {
k = n < 0 ? 0 : n;
}
pos += k;
return k;
}
//支持mark和reset
public boolean markSupported() {
return true;
}
//设置标记为下一次要读的位置
public void mark(int readAheadLimit) {
mark = pos;
}
//设置下一次要读的位置为标记
public synchronized void reset() {
pos = mark;
}
StringInputStream
从字符串或其他String输入流中读出字节数据,继承自ReaderInputStream,持有该一个Reader对象用于读取字符串,然后拆分字符为字节数据读出
//字符输入流
private Reader in;
//编码
private String encoding;
//字符中读剩下的字节的缓冲
private byte[] slack;
//缓冲起始位
private int begin;
public synchronized int read() throws IOException {
if (this.in == null) {
throw new IOException("Stream Closed");
} else {
byte result;
//有上次读剩的缓冲,从缓冲读
if (this.slack != null && this.begin < this.slack.length) {
result = this.slack[this.begin];
if (++this.begin == this.slack.length) {
this.slack = null;
}
//无缓冲,从字符输入流读一个字符到缓冲,返回缓冲第一位
} else {
byte[] buf = new byte[1];
if (this.read(buf, 0, 1) <= 0) {
return -1;
}
result = buf[0];
}
return result & 255;
}
}
FileInputStream
文件输入流,从文件中读取字节数据
public int read() throws IOException {
return read0();
}
//需要本地方法读取文件
private native int read0() throws IOException;
SequenceInputStream
序列字节输入流,持有一组字节输入流,依次进行读出,读完一个切换一个
成员变量 | 含义 |
---|---|
Enumeration<? extends InputStream> e | 持有的字节输入流 |
InputStream in | 当前读的字节输入流 |
public int read() throws IOException {
while (in != null) {
//读当前InputStream,读完了切换
int c = in.read();
if (c != -1) {
return c;
}
nextStream();
}
return -1;
}
final void nextStream() throws IOException {
//关闭现在的输入流
if (in != null) {
in.close();
}
//切换下一个输入流
if (e.hasMoreElements()) {
in = (InputStream) e.nextElement();
if (in == null)
throw new NullPointerException();
}
else in = null;
}
FilterInputStream
FilterInputStream使用代理模式,封装了一个字节输入流对象,在重写的方法中通过调用字节输入流对象的方法读取数据,再通过过滤代码(由子类重写read方法添加)实现对输入数据的过滤
//持有的字节输入流对象
protected volatile InputStream in;
//构造函数
protected FilterInputStream(InputStream in) {
this.in = in;
}
//读取一个字节
public int read() throws IOException {
return in.read();
}
OutputStream
字节输出流,以字节为单位输出
类型 | 作用 | API |
---|---|---|
写 | 写入一个字节 | write(int) |
写入一个字节数组 | read/write(byte[],int offset,lenght) | |
关闭 | 清空缓冲区 | flush() |
关闭流 | close() |
Reader
字符输入流,以字符为单位从程序外部获取数据
类型 | 作用 | API |
---|---|---|
读 | 读出一个字符读出一个字节 | read() |
读出一定长度字符 | read/write(char[],offset,len) | |
跳过 | 跳过一定长度字节开始读 | skip(long n) |
回溯 | 能否标记 | markSupported |
标记当前读的位置 | mark(int readlimit) | |
回到标记开始读 | reset | |
关闭 | 清空缓冲区 | flush() |
关闭流 | close() |
Writer
类型 | 作用 | API |
---|---|---|
写 | 写入一定长度字符 | append/write(char[],offset,len) |
写入一个字符串 | append/write(String s) | |
写入一个字符串的指定区间 | append/write(String s,offset,len) | |
关闭 | 关闭流 | close |
清空流内缓冲 | flush() |
网友评论