22.3 对象流
22,3,1 对象流
ObjectInputStream ObjectOutputStream类分别是InputStream和OutputStream的子类,对象输出流使用writeObject(Object obj)方法,将一个对象obj写入到一个文件,使用readObject()读取一个对象。
构造方法:
ObjectInputStream (InputStream in)
ObjectOutputStream(OutputStream out)
代码示例:
将对象写入文件:
//'序列化'的对象写入文件 OutputStream outputStream = new FileOutputStream(file); ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream); objectOutputStream.writeObject(Object obj); objectOutputStream.close();
从文件读取对象:
//序列化读取对象 InputStream inputStream = new FileInputStream(file); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); Object obj = objectInputStream.readObject(); objectInputStream.close();
注意:当使用对象流写入或者读取对象的时候,必须保证该对象是
序列化
的,这样是为了保证对象能够正确的写入文件,并能够把对象正确的读回程序。什么是对象序列化?
22.3.2 对象序列化
所谓的对象的序列化就是将对象转换成二进制数据流的一种实现手段,通过将对象序列化,可以方便的实现对象的传输及保存。在Java中提供了ObejctInputStream 和ObjectOutputStream这两个类用于序列化对象的操作。用于存储和读取对象的输入输出流类,要想实现对象的序列化需要实现Serializable接口,但是Serializable接口中没有定义任何的方法,仅仅被用作一种标记,以被编译器作特殊处理。
package com.yztc.main;
import java.io.Serializable;
//实现了Serializable接口。序列化
public class Student implements Serializable {
//由编译器自动生成,用来解决不同的版本之间的序列化问题。
private static final long serialVersionUID = -79485540193100816L;
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student() {
super();
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
}
22.3.3 transient(英文单词意思:短暂的,瞬变的)
一旦变量被transient修饰,变量将不再是对象持久化(写到磁盘里持久保存)的一部分,该变量内容在序列化后无法获得访问。(即被transient修饰的变量不会被保存写入文件)
transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。
被transient关键字修饰的成员变量不再能被序列化。
静态变量不管是否被transient修饰,均不能被序列化。
22.4 RandomAccessFile类
RandomAccessFile 类可以说是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。
RandomAccessFile 类支持“随机访问”方式,可以跳转到文件的任意位置处读写数据。在要访问一个文件的时候,不想把文件从头读到尾,而是希望像访问一个数据库一样地访问一个文本文件,这时,使用RandomAccessFile类就是最佳选择。
RandomAccessFile 对象类有个位置指示器,指向当前读写处的位置,当读写n个字节后,文件指示器将指向这n个字节后的下一个字节处。刚打开文件时,文件指示器指向文件的开头处(即0字节处),可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。
RandomAccessFile在数据等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其它的IO 设备,如网络、内存映像等。
以读写的方式打开一个文件时,如果文件不存在,程序会自动创建此文件。
有关RandomAccessFile类中的成员方法及使用说明请参阅JDK文档。常见API如下:
方法名 | 描述 |
---|---|
void close(); | 关闭此随机访问文件流并释放与该流关联的所有系统资源。 |
long getFilePointer(); | 返回此文件中的当前偏移量。 |
void setLength(Long newLength); | (设置临时文件)设置文件的初始字节大小,若写入的字节小于初始大小,则文件大小仍为初始大小,若大小,则为实际写入字节大小。 |
long length(); | 返回此文件的长度。 |
read函数集 | 从文件读 |
void seek(long pos); | 设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取或写入操作。 |
int skipBytes(int n) | 尝试跳过输入的 n 个字节以丢弃跳过的字节。 |
write函数集 | 往文件写 |
22.4.1 RandomAccessFile 类的构造方法
new RandomAccessFile(f, "rw"); // 读写方式,还有rws、rwd
new RandomAccessFile(f, "r"); // 只读方式
其他:
22.4.2 向文件中记忆写入数据
File file = new File("accessFile");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
// 以下向 raf 文件中写数据
raf.writeInt(20);// 占4个字节
raf.writeDouble(8.236598);// 占8个字节
raf.writeShort(395);// 占2个字节
raf.writeUTF("这是一个UTF字符串");// 这个长度为:两个字节+字符串长度总字节,可用readShort()读取出字符串总字节
raf.writeBoolean(true);// 占1个字节
raf.writeLong(2325451l);// 占8个字节
raf.writeUTF("又是一个UTF字符串哈哈");
raf.writeFloat(35.5f);// 占4个字节
raf.writeChar('a');// 占2个字节
raf.close();
22.4.3 从文件中读取随机记忆的文件内容
File file = new File("accessFile");
RandomAccessFile raf = new RandomAccessFile(file, "rw");
System.out.println(raf.readInt());//读取Int数据,指针会往后移动4字节
System.out.println(raf.readDouble());//读取Double数据,指针会往后移动8字节
System.out.println(raf.readUTF());//读取字符串,指针会移到该字符串后
raf.skipBytes(3);//跳过3个字节,也就是跳过上面例子的 boolen 和 short 值。
System.out.println(raf.readLong());//读取long值
short readShort = raf.readShort();//读取字符串的长度
System.out.println("目前指针处的字符串长度为=" + readShort);
raf.skipBytes(readShort);//跳过该字符串
System.out.println(raf.readFloat());//读取float值
System.out.println(raf.readChar());//读取char值
//long length = raf.length();
//System.out.println("文件的总字节数为:"+length);
//long filePointer = raf.getFilePointer();//当前指针的位置,定位到哪个字节了。
//System.out.println("目前字节指针定位在:"+filePointer);
//raf.seek(4);//直接定位到第4个字节处。