目录
一、IO知识体系
二、IO的作用
- 将数据写到文件中,实现数据永久化存储
- 把文件中的数据读取到内存中(Java程序)
I 表示intput ,是数据从硬盘进内存的过程,称之为读数据
O 表示output ,是数据从内存到硬盘的过程。称之为写数据
三、IO的分类
根据数据的流向分为:输入流和输出流。
- 输入流:把数据从硬盘上读取到内存中的流。
- 输出流:把数据从内存 中写出到硬盘上的流。
(抽象基类) | 字节流 | 字符流 |
输入流 | 字节输入流的顶级父类 InputStream |
字符输入流的顶级父类 Reader |
输出流 | 字节输出流的顶级父类 OutputStream |
字符输出流的顶级父类 Writer |
根据数据的类型分为:字节流和字符流。
- 字节流:以字节为单位,操作所有类型的文件,包括音频视频图片等
- 字符流:以字符为单位,只能操作纯文本文件。能用windows记事本打开并能读的懂
区别:字节是给计算机看的,字符才是给人看的
四、编/解码
编码就是把字符转换为字节,而解码是把字节重新组合成字符。
如果编码和解码过程使用不同的编码方式那么就出现了乱码。
- GBK 编码中,中文字符占 2 个字节,英文字符占 1 个字节;
- UTF-8 编码中,中文字符占 3 个字节,英文字符占 1 个字节;
- UTF-16be 编码中,中文字符和英文字符都占 2 个字节。
UTF-16be 中的 be 指的是 Big Endian,也就是大端。相应地也有 UTF-16le,le 指的是 Little Endian,也就是小端。
Java 使用双字节编码 UTF-16be,这不是指 Java 只支持这一种编码方式,而是说 char 这种类型使用 UTF-16be 进行编码。char 类型占 16 位,也就是两个字节,Java 使用这种双字节编码是为了让一个中文或者一个英文都能使用一个 char 来存储。
五、InputStream
IO流以byte(字节)为最小单位,因此也称为字节流。例如,我们要从磁盘读入一个文件,包含6个字节,就相当于读入了6个字节的数据,这6个字节是按顺序读入的,所以是输入字节流。
╔═══════════╗
║ Memory ║
╚═══════════╝
▲
│0x48
│0x65
│0x6c
│0x6c
│0x6f
│0x21
╔═══════════╗
║ Hard Disk ║
╚═══════════╝
1.层次结构
2.重要方法
// 读取下一个字节,如果没有则返回-1
public abstract int read()
// 将读取到的数据放在 byte 数组中,该方法实际上调用read(byte b[], int off, int len)方法
public int read(byte b[])
// 从第 off 位置读取<b>最多(实际可能小于)</b> len 长度字节的数据放到 byte 数组中,流是以 -1 来判断是否读取结束的; 此方法会一直阻止,直到输入数据可用、检测到stream结尾或引发异常为止。
public int read(byte b[], int off, int len)
// JDK9新增:读取 InputStream 中的所有剩余字节,调用readNBytes(Integer.MAX_VALUE)方法
public byte[] readAllBytes()
// JDK11更新:读取 InputStream 中的剩余字节的指定上限大小的字节内容;此方法会一直阻塞,直到读取了请求的字节数、检测到流结束或引发异常为止。此方法不会关闭输入流。
public byte[] readNBytes(int len)
// JDK9新增:从输入流读取请求的字节数并保存在byte数组中; 此方法会一直阻塞,直到读取了请求的字节数、检测到流结束或引发异常为止。此方法不会关闭输入流。
public int readNBytes(byte[] b, int off, int len)
// 跳过指定个数的字节不读取
public long skip(long n)
// 返回可读的字节数量
public int available()
// 读取完,关闭流,释放资源
public void close()
// 标记读取位置,下次还可以从这里开始读取,使用前要看当前流是否支持,可以使用 markSupport() 方法判断
public synchronized void mark(int readlimit)
// 重置读取位置为上次 mark 标记的位置
public synchronized void reset()
// 判断当前流是否支持标记流,和上面两个方法配套使用
public boolean markSupported()
// JDK9新增:读取 InputStream 中的全部字节并写入到指定的 OutputStream 中
public long transferTo(OutputStream out)
3.源码
public abstract class InputStream implements Closeable {
// 当使用skip方法时,最大的buffer size大小
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
// 默认的buffer size
private static final int DEFAULT_BUFFER_SIZE = 8192;
// JDK11中增加了一个nullInputStream,即空模式实现,以便可以直接调用而不用判空(可以看如下的补充说明)
public static InputStream nullInputStream() {
return new InputStream() {
private volatile boolean closed;
private void ensureOpen() throws IOException {
if (closed) {
throw new IOException("Stream closed");
}
}
@Override
public int available () throws IOException {
ensureOpen();
return 0;
}
@Override
public int read() throws IOException {
ensureOpen();
return -1;
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
ensureOpen();
return -1;
}
@Override
public byte[] readAllBytes() throws IOException {
ensureOpen();
return new byte[0];
}
@Override
public int readNBytes(byte[] b, int off, int len)
throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
ensureOpen();
return 0;
}
@Override
public byte[] readNBytes(int len) throws IOException {
if (len < 0) {
throw new IllegalArgumentException("len < 0");
}
ensureOpen();
return new by