概念
I/O是Input和Output的缩写,Java中的I/O指的是处理输入与产生输出的工具类。
I/O指的是内存与存储介质之间的数据交换,广义的存储介质包括磁盘、网络等。
流Stream:在Java中通常以流的方式来处理I/O,一个流指的是一个字节序列。
Java提供的输入输出流都在java.io包中。
分类
按照传输方向分为输入流和输出流
按照传输内容分为字节流和字符流
按照目的分为:
- 文件读取:files
- 网络:network
- 内存中的缓存获取:in-memory buffers(arrays)
- 线程中通信:pipes
- 缓存:buffering
- 过滤:filtering
- 解析:parsing
- 读写文本
- 读写基本数据类型
- 读写对象:
- system.in、system.out、system.error
输入输出流
在Java API中,可以从其中读取一个字节序列的对象称为输入流,而可以向其中写入一个字节序列的对象称为输出流。这些字节序列的来源地和目的地可以是文件(通常都是文件),也可以是网络连接,甚至是内存块。抽象类InputStream和OutputStream构成了输入/输出类层次结构的基础。
因为面向字节的流不便于处理以Unicode形式存储的信息,所以从抽象类Reader和Writer中继承出来了一个专门用于处理Unicode字符的单独的类层次结构。这些类拥有的读入和写出操作都是基于两字节的Char值而不是基于byte值的。
输入流InputStream:Java程序使用输入流从数据源读取数据,数据源可以是文件、数组、外部设备、socket。
输出流OutputStream:java程序使用输出流将数据写入到目的地,目的地可以是文件、数组、外部设备、socket。
从输入流到输出流的整个过程如下图所示:
InputStream
字节输入流用于从流中读取单个字节或字节数组。
字节输入流有以下实现子类:
FileInputStream
ByteArrayInputStream
FilterInputStream
DataInputStream
BufferedInputStream
PushBackInputStream
PipedInputStream
可以和PipedOutputStream连接,连接口可以读取PipedOutputStream写入的字节
ObjectInputStream
SequenceInputStream
接收多个输入流,对其进行concat,形成一个新的输入流
字节输出流
这个抽象类是所有表示字节输出流的类的超类。
子类实现这个抽象类的时候必须实现write()抽象方法,写入一个字节到输出流中。
public abstract class OutputStream implements Closeable, Flushable {
// 将特定的字节b写入到输出流,忽略b的高24位,将低8位写入输出流。
public abstract void write(int b) throws IOException;
// 将指定字节数组写入到输出流,与write(b, 0, b.len)具有相同的效果。
public void write(byte b[]) throws IOException {};
// 将指定字节数组b从off偏移开始的最多len个字节写入到输出流。
public void write(byte b[], int off, int len) throws IOException {};
public void flush() throws IOException {};// 刷新此输出流,强制将缓存的输出字节写出。
public void close() throws IOException {};// 关闭输出流,释放系统资源。
}
OutputStream的继承层次
字符流
字符输入流 Reader
// 用于读取字符流的抽象类
public abstract class Reader implements Readable, Closeable {
protected Object lock;
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
public int read(java.nio.CharBuffer target) throws IOException {}
public int read() throws IOException {}
public int read(char cbuf[]) throws IOException {}
// 从输入流读取指定长度的字符到字符数组,子类必须实现该方法
abstract public int read(char cbuf[], int off, int len) throws IOException;
// 跳过指定长度的字符
public long skip(long n) throws IOException {};
// 流是否准备好被读取
public boolean ready() throws IOException {};
// 流是否支持mark()操作
public boolean markSupported() {};
// 标记流的当前位置
public void mark(int readAheadLimit) throws IOException {};
// 重置流。如果流已被标记,则尝试将其重新定位在标记处。如果流尚未被标记,则尝试以某种方式重置,比如将其重新定位到起点。
// 并未所有字符输入流都支持reset操作,还有些支持reset但是不支持mark操作。
public void reset() throws IOException {};
// 关闭流,释放相关的系统资源,子类必须实现该方法。
abstract public void close() throws IOException;
}
字符输出流 Writer
// 用于写入字符流的抽象类
public abstract class Writer implements Appendable, Closeable, Flushable {
private char[] writeBuffer;// 用于保存字符串和单个字符写入的临时缓冲区
private static final int WRITE_BUFFER_SIZE = 1024;// writeBuffer 的大小,必须 >= 1
// 用于同步此流上的操作的对象。为了提高效率,字符流对象可以使用除自身之外的对象来保护临界区。因此,子类应该使用此字段中的对象而不是 this 或同步方法。
protected Object lock;
// 创建一个新的字符流编写器,其临界区将在编写器本身上同步。
protected Writer() {
this.lock = this;
}
// 创建一个新的字符流编写器,其临界区将在给定对象上同步。
protected Writer(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
// 写入单个字符。要写入的字符包含在给定整数值的低16位中;高16位被忽略。实际调用write(writeBuffer, 0, 1);
public void write(int c) throws IOException {}
// 写入字符数组,实际调用write(cbuf, 0, cbuf.length)
public void write(char cbuf[]) throws IOException {}
// 写入字符数组从偏移位置off开始长度为len的部分。子类必须实现该方法。
abstract public void write(char cbuf[], int off, int len) throws IOException;
// 写入字符串,实际调用write(str, 0, str.length());
public void write(String str) throws IOException {}
// 写入字符串的子串
public void write(String str, int off, int len) throws IOException {};
// 将指定的字符序列附加到此编写器。
public Writer append(CharSequence csq) throws IOException {};
public Writer append(CharSequence csq, int start, int end) throws IOException {};
public Writer append(char c) throws IOException {};
abstract public void flush() throws IOException;
abstract public void close() throws IOException;
}
字节流和字符流的转换
InputStreamReader:将字节输入流 转换成 字符输入流
// 字节流到字符流的桥梁。读取字节,编码成为字符。内部方法调用的都是StringDecoder的方法。
public class InputStreamReader extends Reader {
private final StringDecoder sd;
// 基于 字节输入流 和 字符集 创建 字符输入流
public InputStreamReader(InputStream in) // 基于默认字符集的构造函数
public InputStreamReader(InputStream in, String charsetName) //基于指定名称字符集的构造函数
public InputStreamReader(InputStream in, Charset cs) //基于指定字符集的构造函数
public InputStreamReader(InputStream in, CharsetDecoder dec) {} //
public String getEncoding() {}
public int read() throws IOException {} // 读取单个字节
public int read(char cbuf[], int offset, int length) throws IOException {} // 读取字节数组
public boolean ready() throws IOException {}
public void close() throws IOException {}
}
public class StreamDecoder extends Reader {}
OutputStreamWriter:将字节输出流 转换成 字符输出流
public class OutputStreamWriter extends Writer {
private final StreamEncoder se;
// 基于 字节输出流 和 字符集 创建 字符输出流
public OutputStreamWriter(OutputStream out) {}
public OutputStreamWriter(OutputStream out, String charsetName) {}
public OutputStreamWriter(OutputStream out, Charset cs) {}
public OutputStreamWriter(OutputStream out, CharsetEncoder enc) {}
public String getEncoding() {}
void flushBuffer() throws IOException {}
public void write(int c) throws IOException {} // 写入字符
public void write(char cbuf[], int off, int len) throws IOException {} // 写入字符数组
public void write(String str, int off, int len) throws IOException {} // 写入字符串
public void flush() throws IOException {}
public void close() throws IOException {}
}
public class StreamEncoder extends Writer {}
节点流
缓冲区
public class ByteArrayInputStream extends InputStream{} // 字节数组输入流
public class ByteArrayOutputStream extends OutputStream{} // 字节数组输出流
public class CharArrayReader extends Reader{} // 字符数组输入流
public class CharArrayWriter extends Writer{} // 字符数组输出流
文件
public class FileInputStream extends InputStream{}
public class FileOutputStream extends OutputStream{}
public class FileReader extends InputStreamReader{}
public class FileWriter extends OutputStreamWriter{}
管道
管道用于线程间的通信
public class PipedInputStream extends InputStream{}
public class PipedOutputStream extends OutputStream{}
系统输入输出
Java中存在三个系统标准流,他们在JVM启动时就会自动实例化。
public final class System {
public final static InputStream in = null;
public final static PrintStream out = null;
public final static PrintStream err = null;
}
System.in:将键盘作为输入的标准输入流
System.out:将控制台作为输出的标打印出流
System.err:将控制台作为输出的错误打印流
处理流
过滤流
过滤流接收输入输出流,进行数据的转换或者提供附加功能。
public class FilterInputStream extends InputStream{}
public class FilterOutputStream extends OutputStream{}
public class FilterReader extends Reader{}
public class FilterWriter extends Writer{}
缓冲流
缓冲流接收一个输入流或输出流。
public class BufferedInputStream extends FilterInputStream{}
public class BufferedOutputStream extends FilterOutputStream{}
打印流
打印流是输出流,包括字节输出流和字符输出流。
public class PrintStream extends FilterOutputStream{}
public class PrintWriter extends FilterWriter{}
Sequence流
Sequence输入流可以接收多个输入流,并将它们的内容写入到新的输入流中去。
public class SequenceInputStream extends InputStream{
SequenceInputStream(InputStream s1, InputStream s2)
}