IO流(三)~ 其他流
一、序列化
1. 序列化流
-
什么是序列化流
把堆内存中的 Java 对象数据,通过某种方式把对象存储到磁盘文件中或者传递给其他网络节点(在网络上传输),这个过程称为序列化。通俗来说就是将数据结构或对象转换成二进制串的过程。 -
构造方法
//可以将Java程序中的对象写到文件中 //参数:out 参数要传递字节输出流 ObjectOutputStream(OutputStream out)
*注意:要使用序列化流向文件中写的对象,必须实现 Serializable 接口
二、反序列化流
- 什么是反序列化流
把磁盘文件中的对象数据或者把网络节点上的对象数据,恢复成Java对象模型的过程。也就是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。 - 构造方法
//可以将文件中的对象读取到 Java 程序中
//参数:in 参数要传递字节输入流
ObjectInputStream(InputStream in)
*注意:调用readObject
方法读取对象时,对象所对应的类不存在,那么会报错(ClassNotFoundException)
3. 案例-向流中写入对象
分析:
1.创建序列化流,用来写入对象。
2.调用 writeObject 方法,写对象。
3.释放资源。
代码:
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//1. 创建序列化流,用来写
String path = "E:/person.txt";
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(path);
//2. 调用writeObject方法,写对象
Person p = new Person("张三丰", 100);
oos.writeObject(p);
//3. 释放资源。
oos.close();
}
}
/**
* 序列化类
*/
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
4. 案例-从文件中读取对象
分析:
1.创建 ObjectInputStream 反序列化流。
2.调用 readObject 方法,读取对象。
3.释放资源。
代码:
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//创建反序列化流
String path = "E:/person.txt";
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path));
//从文件中读取对象
Object obj = ois.readObject();
Person person = (Person) obj;
System.out.println("姓名:" + person.getName() + "\n年龄:" + person.getAge());
//释放资源
ois.close();
}
}
/**
* 序列化类
*/
public class Person implements Serializable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
三、文件随机访问流
1. 概述
此类的实例支持对随机访问文件的读取和写入。随机访问文件的行为类似存储在文件系统中的一个大型 byte 数组。存在指向该隐含数组的光标或索引,称为文件指针;输入操作从文件指针开始读取字节,并随着对字节的读取而前移此文件指针。如果随机访问文件以读取/写入模式创建,则输出操作也可用;输出操作从文件指针开始写入字节,并随着对字节的写入而前移此文件指针。写入隐含数组的当前末尾之后的输出操作导致该数组扩展。该文件指针可以通过 getFilePointer 方法读取,并通过 seek 方法设置。
通常,如果此类中的所有读取例程在读取所需数量的字节之前已到达文件末尾,则抛出 EOFException(是一种 IOException)。如果由于某些原因无法读取任何字节,而不是在读取所需数量的字节之前已到达文件末尾,则抛出 IOException,而不是 EOFException。需要特别指出的是,如果流已被关闭,则可能抛出 IOException。
RandomAccessFile有两个构造器,其实这两个构造器基本相同,只是指定文件的形式不同而已,一个使用String参数来指定文件名,一个使用File参数来指定文件本身。除此之外,创建RandomAccessFile对象还需要指定一个mode参数。该参数指定RandomAccessFile的访问模式,有以下4个值:
1."r"以只读方式来打开指定文件夹。如果试图对该RandomAccessFile执行写入方法,都将抛出IOException异常。
2."rw"以读写方式打开指定文件。如果该文件尚不存在,则试图创建该文件。
3."rws"以读写方式打开指定文件。相对于”rw” 模式,还要求对文件内容或元数据的每个更新都同步写入到底层设备。
4."rwd"以读写方式打开指定文件。相对于”rw” 模式,还要求对文件内容每个更新都同步写入到底层设备。
2. 案例-指定位置数据读取
分析:
1.创建随机访问文件输入流
2.打印访问文件的初始指针位置
3.移动指针
4.读取数据
5.每次读取的数据长度
代码:
public class Test {
public static void main(String[] args) throws Exception {
//创建随机访问文件输入流
RandomAccessFile rf = new RandomAccessFile("a.txt", "rw");
//打印访问文件的初始指针位置0
System.out.println("文件开头:" + rf.getFilePointer());
//移动指针
rf.seek(3); //1为一个字节
//读取数据
byte[] b = new byte[1024];
//每次读取的数据长度
int len = 0;
while ((len = rf.read(b)) != -1) {
System.out.println(new String(b, 0, len));
}
}
}
3. 案例-指定位置数据写入
分析:
1.创建随机访问文件输入流
2.移动指针,到文件最后
3.添加数据
代码:
public class Test {
public static void main(String[] args) throws Exception {
//创建随机访问文件输入流
RandomAccessFile rf = new RandomAccessFile("a.txt", "rw");
//移动指针,到文件最后
rf.seek(rf.length());
//添加数据
rf.write("添加的数据".getBytes());
}
}