Java流笔记之对象序列化

java.io.Serializable

java.io.Externalizable

序列化机制可以将实现序列化的对象转换成字节序列,使得对象能脱离java程序存在.如果要使一个对象是可序列化的,需要实现Serializable接口或者Externalizable接口之一.

使用Serializable标记接口实现对象的序列化很简单,只需要目标对象类实现Serializable接口即可,无需实现其方法.如果希望让对象的一些实例变量不被序列化,可以使用transient修饰符修饰.

1.将student对象序列化并储存在磁盘中并读取还原成对象

import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.Serializable;
import java.lang.ClassNotFoundException;

public  class SerializeTest{
	public static void main(String[] args) {
		try(
			ObjectOutputStream oop = new ObjectOutputStream(new FileOutputStream("log.txt"));
			ObjectInputStream oip = new ObjectInputStream(new FileInputStream("log.txt"));
		){
			Student s1 = new Student(3,"李华",1998);
			oop.writeObject(s1);
			Student s = (Student)oip.readObject();
			System.out.println(s.age + "  " + s.name + " " + s.year);
		}catch(Exception e){
			e.printStackTrace();
		}
	}
}
class Student implements Serializable{
	int age;
	transient String name;
	int year;
	Student(int age, String name, int year){
		this.age = age;
		this.name = name;
		this.year = year;
	}
}
运行结果:(name用transient修饰,并未被序列化写入到磁盘)
3  null 1998
[Finished in 0.9s]

使用transient修饰的实例成员会被排除在序列化机制外,导致在反序列化时无法获得该实例成员的值.除了transient修饰符之外,Java还提供了自定义序列化机制,通过自动序列化机制,可以使程序自定义控制序列化流程.自定义序列化包含三个方法:

private void writeObject(ObjectOutputStream out) //负责写入对象 默认会调用out.defaultWriteObject()方法
private void readObject(ObjectInputStream in) //负责读取恢复对象 默认会调用in.defaultReadObject()方法
private void readObjectNoDate() //当序列流不完整时,负责初始化反序列化对象

 **注意**

  1. 如果使用序列化向一个文件写入了多个对象,那么读取时是按照写入顺序读取.
  2. 若可序列化对象拥有多个父类,那么这些父类要么有无参的构造器,要么也是序列化的,否则就会抛出InvalidClassException异常.另外,如果父类是不可序列化但有无参数的构造器,则父类中定义的成员变量值不会序列化到二进制流中.
  3. 若类的成员变量不是基本类型或者String,而是其他的引用类型,则这个引用类型也要是可序列化,否则该类无法序列化.(因为在序列化对象时,对象的所有成员变量也会被序列化).
  4. JAVA序列化机制采用了特殊的算法
    • 所有保存到磁盘的对象拥有一个特殊的序列化编号
    • 在程序进行序列化对象之前会检查该对象是否被序列化过,只有在该对象在(本次java虚拟机)未被序列化过时才会将该对象转换成字节系列.
    • 若该对象已经被序列化过,则程序会直接输出该对象的序列化编号.
    • **注意**在对可变对象进行序列化时一定要注意,如果在序列化可变对象后再改变该对象并且进行序列化,程序只会输出该对象改变前的序列化编号,并不会将改变过的对象重新序列化输出.

Java流笔记之RandomAccessFile

java.io.RandomAccessFile

RandomAccessFile是java的一个文件内容访问类,特点是支持”随机访问”,但只能对文件进行操作.
构造方法:

RandomAccessFile(File file/String fileName, String mode): mode为读写模式,分别有:
"r":只读,若写会抛出IOException
"rw":读写,若文件不存在则会创建
"rwd":读写,内容更新同步写到底层设备
"rws":读写,内容和元数据更新同步写到底层设备

常用方法:

long getFilePointer():返回文件中指针的位置
void seek(long index):将指针定位到index位置
void readXXX() void writeXXX() 读写

1.读取文件

import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
public class RandomAccessFileTest{
	    public static void main(String[] args) {
	    try(
		    RandomAccessFile raf = new             
            RandomAccessFile("RandomAccessFileTest.java","rw");
		    ){
		    System.out.println("文件指针初始位置 :     "+raf.getFilePointer());
		    byte[] buffer = new byte[32];
		    int hasRead;
		    while ((hasRead = raf.read(buffer)) > 0) {
		    	    System.out.print(new String(buffer,0,hasRead));
		    }
	    }catch (IOException e) {
	    	e.printStackTrace();
	    }
    }
}

2.追加内容

import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;
public class RandomAccessFileTest{
	public static void main(String[] args) {
		try(
			RandomAccessFile raf = new RandomAccessFile("RandomAccessFileTest.java","rw");
		){
			System.out.println("文件字节数 : " + raf.length());
			raf.seek(raf.length());
			System.out.println("当前文件指针位置: " + raf.getFilePointer());
			raf.write("//这是添加的内容".getBytes());

		}catch (IOException e) {
			e.printStackTrace();
		}
	}
}//这是添加的内容

3.修改内容

**注意:直接修改文件指针内容会直接覆盖内容**
import java.io.RandomAccessFile;
import java.io.IOException;
import java.io.FileNotFoundException;//这是添加的新内容//这是添加的新内容
public class RandomAccessFileTest{
	public static void main(String[] args) {
		try(
			RandomAccessFile raf = new RandomAccessFile("RandomAccessFileTest.java","rw");
		){
			System.out.println(raf.getFilePointer());
			raf.seek(101);
			//将剩余内容缓存到content
			byte[] buffer = new byte[1024];
			int hasRead;
			String content = "";
			while ( (hasRead = raf.read(buffer)) > 0) {
				content += new String(buffer,0,hasRead);
			}
			System.out.println(content);
			raf.seek(101);
			//开始修改内容
			raf.write("//这是添加的新内容".getBytes());
			raf.write(content.getBytes());
		}catch (IOException e) {
			e.printStackTrace();
		}
	}
}//这是添加的内容