1.ObjectInputStream 和 ObjectOutputStream
2.作用:用于存储和读取基本数据类型数据或对象的处理流。它的强大之处就是可以把Java中的对象写入到数据源中,也能把对象从数据源中还原回来。
3.要想一个java对象是可序列化的,需要满足相应的要求。见Person.java
4.序列化机制:
对象序列化机制允许把内存中的Java对象转换成平台无关的二进制流,从而允许把这种二进制流持久地保存在磁盘上,或通过网络将这种二进制流传输出到另一个网络节点。当其它程序获取了这种二进制流,就可以恢复成原来的Java对象。
public class ObjectInputOutputStreamTest {
/*
序列化过程:将内存中的java对象保存到磁盘中或通过网络传输出去。
使用ObjectOutputStream实现
*/
@Test
public void testObjectOutputStreamtest() {
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("我爱北京天安门"));
oos.flush(); //刷新操作
oos.writeObject(new Person("刘德华", 23));
oos.flush();
oos.writeObject(new Person("张学友", 18, 1001, new Account(5000)));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
反序列化:将磁盘文件中的对象还原为内存中的java对象。
使用ObjectInputStream实现
*/
@Test
public void testObjectInputStreamTest() {
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object obj = ois.readObject();
String str = (String) obj;
Person p1 = (Person) ois.readObject();
Person p2 = (Person) ois.readObject();
System.out.println(str); //我爱北京天安门
System.out.println(p1); //Person{name='刘德华', age=23, id=0, acct=null}
System.out.println(p2); //Person{name='张学友', age=18, id=0, acct=Account{balance=5000.0}}
//因为id是static修饰的成员变量,所以不能进行序列化
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Preson类需要满足如下的要求,方可序列化
1.需要实现接口:Serializable
2.当前类提供一个全局常量:serialVersionUID
3.除了当前Person类需要实现Serializable接口之外,还必须保证其内部的所有属性也必须是可序列化的。(默认情况下,基本数据类型可序列化)
补充:ObjectOutputStream和ObjectInputStream不能序列化static和transient修饰的成员变量。
public class Person implements Serializable {
public static final long serialVersionUID = 4787639798979L;
private String name;
private int age;
private static int id;
private Account acct;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public Person(String name, int age, int id) {
this.name = name;
this.age = age;
this.id = id;
}
public Person(String name, int age, int id, Account acct) {
this.name = name;
this.age = age;
this.id = id;
this.acct = acct;
}
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;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Account getAcct() {
return acct;
}
public void setAcct(Account acct) {
this.acct = acct;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", id=" + id +
", acct=" + acct +
'}';
}
}
class Account implements Serializable {
public static final long serialVersionUID = 982348762387L;
private double balance;
public Account() {
}
public Account(double balance) {
this.balance = balance;
}
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
@Override
public String toString() {
return "Account{" +
"balance=" + balance +
'}';
}
}
1.RandomAccessFile直接继承于java.lang.Object类,实现了DataInput和DataOutput接口。
2.RandomAccessFile既可以作为一个输入流,又可以作为一个输出流。
3.RandomAccessFile作为输出流时:
如果写出到的文件不存在,则在执行过程中自动创建;
如果写出到的文件已存在,则会对原有文件内容进行覆盖。(默认情况下,从头开始覆盖)
4.可以通过相关的操作,实现RandomAccessFile“插入”数据的效果。
public class RandomAccessFileTest {
//读取数据
@Test
public void test1() {
RandomAccessFile raf1 = null;
RandomAccessFile raf2 = null;
try {
//1.造流
raf1 = new RandomAccessFile(new File("2022.06.25.jpg"), "r");
raf2 = new RandomAccessFile(new File("2022.06.25-random.jpg"), "rw");
//2.读写过程
byte[] buffer = new byte[1024];
int len;
while ((len = raf1.read(buffer)) != -1) {
raf2.write(buffer, 0, len);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//3.关闭流
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (raf2 != null) {
try {
raf2.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//写入数据
@Test
public void test2() {
RandomAccessFile raf1 = null;
try {
raf1 = new RandomAccessFile(new File("hello.txt"), "rw");
raf1.seek(3); //将指针调到角标为3的位置
raf1.write("xyz".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
使用RandomAccessFile实现数据的插入效果
*/
@Test
public void test3() {
RandomAccessFile raf1 = null;
try {
raf1 = new RandomAccessFile(new File("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));
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
//将StringBuilder中的数据写入到文件中
raf1.write(builder.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//将StringBuilder替换为ByteArrayOutputStream
@Test
public void test4() {
RandomAccessFile raf1 = null;
try {
raf1 = new RandomAccessFile(new File("hello.txt"), "rw");
raf1.seek(3); //将指针调到角标为3的位置
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[10];
int len;
while ((len = raf1.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
//调回指针,写入“xyz”
raf1.seek(3);
raf1.write("xyz".getBytes());
raf1.write(baos.toString().getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (raf1 != null) {
try {
raf1.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
String toString():返回调用Path对象的字符串表示形式
boolean startsWith(String path):判断是否以path路径开始
boolean endsWith(String path):判断是否以path路径结束
boolean isAbsolute():判断是否是绝对路径
Path getParent():返回Path对象包含整个路径,不包含Path对象指定的文件路径
Path getRoot():返回调用Path对象的根路径
Path getFileName():返回与调用Path对象关联的文件名
int getNameCount():返回Path根目录后面元素的数量
Path getName(int idx):返回指定索引位置idx的路径名称
Path toAbsolutePath():作为绝对路径返回调用Path对象
Path resolve(Path p):合并两个路径,返回合并后的路径对应的Path对象
File toFile():将Path转化为File类的对象