- 对象序列化机制允许把内存中的java对象转化为平台无关的二进制流,从而允许把这种二进制流持久地保存到磁盘中,或通过网络将这种二进制流传输到另一个网络节点(序列化)。当其他程序获取了这种二进制流,就可以恢复成原来的java对象(反序列化)。
- ObjectOutputStream与ObjectIntputStream:序列化的好处在于可将任何实现了Serializable接口的对象转化为字节数据,将其在保存和传输是可被还原。
- 类需要满足如下要求才可以序列化(见示例代码1):
- 1)需要实现接口:Serializable(一个标识接口)
- 2)需要提供一个全局常量
- 3)除当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也是可序列化的
- 4)默认情况下,基本数据类型也是可序列化的
- 5)不能序列化static和transient修饰的成员变量
RandomAccessFile类:
1)直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
2)它既可以作为一个输入流又可以作为一个输出流
(Test1)将a011.jpg文件复制了一份,命名为a0101,jpg
(Test2)如果RandomAccessFile类作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建
写出到的文件如果存在,这会对原文件内容进行覆盖(默认从头覆盖)
(Test3)实现插入效果(麻烦)
应用:我们可以用RandomAccessFile类来实现一个多线程断点下载的功能,(下载工具)下载前会建立两个临时文件,一个与被下载文件大小相同的空文件,一个记录文件指针的位置文件,每次暂停的时候都会保存上一次指针,然后断点下载的时候会从上一次的地方下载。
- 有时可以直接使用第三方提供的jar包简化开发:如commons-io-2.5
示例代码1:
//Person类需要满足如下要求才可以序列化
//1、需要实现接口:Serializable(一个标识接口)
//2、需要提供一个全局常量
//3、除当前Person类需要实现Serializable接口之外,还必须保证其内部所有属性也是可序列化的
//默认情况下,基本数据类型也是可序列化的
//不能序列化static和transient修饰的成员变量
public class Person implements Serializable {
public static final long serialVersionUID = 4234252L;//序列版本号
private String name;
private int age;
Account account;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, Account account) {
this.name = name;
this.age = age;
this.account = account;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", account=" + account +
'}';
}
public String getName(){
return name;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public int getAge(){
return age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
}
class Account implements Serializable{
public static final long serialVersionUID = 52L;//序列版本号
private double banlence;
public Account(double banlence) {
this.banlence = banlence;
}
@Override
public String toString() {
return "Account{" +
"banlence=" + banlence +
'}';
}
public void setBanlence(double banlence) {
this.banlence = banlence;
}
public double getBanlence() {
return banlence;
}
}
序列化与反序列化
public class ObjectStream {
// 序列化过程
@Test
public void testOutputStream(){
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("test.dat"));
oos.writeObject(new String("I love you "));
oos.flush();//刷新
oos.writeObject(new Person("liu",22));
oos.flush();//刷新
oos.writeObject(new Person("liu",22,new Account(5000)));
oos.flush();//刷新
} catch (IOException e) {
e.printStackTrace();
} finally {
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 反序列化过程:将磁盘文件中的对象还原为内存中的一个java对象
@Test
public void testInputStream(){
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("test.dat"));
Object obj = ois.readObject();
String str = (String)obj;
Person p = (Person)ois.readObject();
Person p1 = (Person)ois.readObject();
System.out.println(str);
System.out.println(p);
System.out.println(p1);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if(ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Test1与Test2与Test3代码:
//RandomAccessFile类1、直接继承于java.lang.Object类,实现了DataInput和DataOutput接口
//2、它既可以作为一个输入流又可以作为一个输出流
//(Test1)将a011.jpg文件复制了一份,命名为a0101,jpg
//(Test2)如果RandomAccessFile类作为输出流时,写出到的文件如果不存在,则在执行过程中自动创建
//写出到的文件如果存在,这会对原文件内容进行覆盖(默认从头覆盖)
//(Test3)实现插入效果(麻烦)
public class RandomAccessFileTest {
@Test
public void Test1(){
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
raf1 = new RandomAccessFile(new File("a010.jpg"),"r");
raf2 = new RandomAccessFile(new File("a0101,jpg"),"rw");
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1){
raf2.write(buffer,0,len);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(raf1 != null){
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Test
public void Test2() throws Exception {
RandomAccessFile raf1 = new RandomAccessFile("Hello.txt","rw");
// RandomAccessFile raf2 = new RandomAccessFile("Hello.txt","rw");
raf1.write("abcxyzsdf".getBytes());
raf1.close();
}
@Test
public void Test3() throws IOException {
RandomAccessFile raf1 = new RandomAccessFile("Hello.txt","rw");
raf1.seek(3);//将指针调到3的位置
// 保存指针3后面的所有数据到StringBuilder中
StringBuilder builder = new StringBuilder((int)new File("Hello.txt").length());
byte[] buffer = new byte[20];
int len;
while ((len = raf1.read(buffer)) != -1){
builder.append(new String(buffer,0,len));
}
// 调回指针,写入“liu”
raf1.seek(3);
raf1.write("liu".getBytes());
// 写入之前位置3后面的数据
raf1.write(builder.toString().getBytes());
raf1.close();
}
}