Java I/O工作机制:
注:简要笔记,示例代码可能较少,甚至没有。
1、Java 的 I/O 类库的基本架构。
Java 的 I/O 操作类在包 java.io 下,大概有将近80个类,这些类大概可以分为如下四组。
- 基于字节操作的 I/O 接口:InputStream 和 OutputStream 。
- 基于字符操作的 I/O 接口:Writer 和 Reader 。
- 基于磁盘操作的 I/O 接口:File。
- 基于网络操作的 I/O 接口:Socket。
1.1、基于字节的 I/O 操作接口
基于字节的 I/O 操作接口输入和输出分别是:InputStream 和 OutputStream 。InputStream 的类层次如下:
输入流根据数据类型和操作方式又被划分为若干个子类,每个子类分别处理不同操作类型。OutputStream 的类层次结构也类似,如下图:
1.2、基于字符的 I/O 操作接口
下图是写字符的 I/O 操作接口涉及的类,Writer 类提供了一个抽象方法 write(char cbuf[],int off,int len)。
读字符的操作接口也有类似的结构,如下图:
读字符的操作接口是 int read(char cbuf[],int off,int len),。返回读到的n个字节数,不管是 Writer 还是 Reader 类,它们都只定义了读取或写入的数据字符的方式,也就是怎么写或读。
1.3、字节与字符的转化接口
字符到字节需要转化,其中,读的转化过程如下:
InputStreamReader 类是字节到字符的转化桥梁,InputSream 到 Reader 的过程要指定编码字符集,否则将采用操作系统默认字符集,很可能会出现乱码问题。SteamDecoder 正是完成字节到字符的解码的实现类。类似如下代码读到一个文件时:
try {StringBuffer str = new StringBuffer();char[] buf = new char[1024];FileReader f = new FileReader("file");while (f.read(buf) > 0) {str.append(buf);}str.toString();}catch (IOException e){}
FileReader 类就是按照上面的工作方式读取文件的,FileReader 继承了 InputStramReader 类,实际上时读取文件流,然后通过 StreamDecoder 解码成 char ,只不过这里的编码字符集时默认字符集。
写入也是类似的过程:
通过 OutputStreamWriter 类完成字符到字节的编码过程,由 StreamEncoder 完成编码过程。
2、磁盘 I/O 工作机制:
2.1、几种访问文件的方式
- 标准访问文件方式。
- 直接 I/O 方式。
- 同步访问文件方式。
- 异步访问文件方式。
- 内存映射方式。
2.2、Java 访问磁盘文件
当传入一个文件路径时,将会根据这个路径创建一个 File 对象来表示这个文件,然后根据这个 File 对象创建真正读取文件的操作对象,这时将会真正创建一个关联真实存在的磁盘文件的文件描述符 FileDescriptor,通过这个对象可以直接控制这个磁盘文件,。
2.3、Java 序列化技术
Java 序列化就是将一个对象转化为一串二进制表示的字节数组,通过保存或转移这些字节数据来达到持久化的目的。需要持久化,对象必须继承 java.io.Serializable 接口。反序列化则是相反的过程,将这个字节数组再重新构造成对象。我们知道反序列化时,必须有原始类作为模板,才能将这个对象还原,从这个过程我们可以猜测,序列化的数据并不像 class 文件那样保存类的完整的结构信息。下面是一个简单的序列化的代码:
public class Serialize implements Serializable {private static final long serialVersionUID = - 6849794470754660011L;public int num = 1390;public static void main(String[] args) {try {FileOutputStream fos = new FileOutputStream("d:/serialize.dat");ObjectOutputStream oos = new ObjectOutputStream(fos);Serialize serialize = new Serialize();oos.writeObject(serialize);oos.flush();oos.close();} catch (IOException e) {e.printStackTrace();}}
}
序列化的文件二进制字节数据如下:
-
第一部分是反序列化文件头。
-
第二部分是要反序列化的类的描述,在这里是 Serialize 类。
-
第三部分是对象中各个属性项的描述
-
第四部分输出该对象的父类信息描述,这里没有父类,如果有,数据格式与第二部分一样。
-
第五部分输出对象的属性项的实际值,如果属性项是一个对象,那么这里还将序列化这个对象,规则和第二部分一样。