1. ObjectInputStream和ObjectOutputStream
package io;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* 1、序列化是干什么的?
简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
2、什么情况下需要序列化
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;
3、当对一个对象实现序列化时,究竟发生了什么?
在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:
Foo myFoo = new Foo();
myFoo .setWidth(37);
myFoo.setHeight(70);
当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对 象。
FileOutputStream fs = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(myFoo);
4、实现序列化(保存到一个文件)的步骤
a)Make a FileOutputStream
java 代码
FileOutputStream fs = new FileOutputStream("foo.ser");
b)Make a ObjectOutputStream
java 代码
ObjectOutputStream os = new ObjectOutputStream(fs);
c)write the object
java 代码
os.writeObject(myObject1);
os.writeObject(myObject2);
os.writeObject(myObject3);
d) close the ObjectOutputStream
java 代码
os.close();
5、举例说明
java 代码
import java.io.*;
public class Box implements Serializable
{
private int width;
private int height;
public void setWidth(int width){
this.width = width;
}
public void setHeight(int height){
this.height = height;
}
public static void main(String[] args){
Box myBox = new Box();
myBox.setWidth(50);
myBox.setHeight(30);
try{
FileOutputStream fs = new FileOutputStream("foo.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(myBox);
os.close();
}catch(Exception ex){
ex.printStackTrace();
}
}
}
6、相关注意事项
a)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
b)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;
c)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:
1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输 等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。
2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分 配,而且,也是没有必要这样实现。
* @author asus
*
*/
public class ObjectStreamDemo {
public static void main(String[] args) {
try {
writeObj();
readObj();
} catch (Exception e) {
e.printStackTrace();
}
}
private static void writeObj() throws IOException{
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("E:\\BaiduYunDownload\\FILE\\obj")));
oos.writeObject(new Person("test",99));
oos.close();
}
private static void readObj() throws IOException, ClassNotFoundException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E:\\BaiduYunDownload\\FILE\\obj")));
Person p = (Person)ois.readObject();
System.out.println(p.toString());
ois.close();
}
}
//序列化
class Person implements Serializable{
//手动匹配序列号
private static final long serialVersionUID = 42L;
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String toString(){
return name+".."+age;
}
}
2. PipedInputStream 和PipedOutputStream
package io;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/*
* 管道流对象 PipedInputStream PipedOutputStream,输入输出可以直接连接的特殊流对象,应该通过多线程使用以免死锁。
*/
public class PipedStreamDemo {
public static void main(String[] args) {
//创建管道流对象
PipedInputStream in = new PipedInputStream();
PipedOutputStream out = new PipedOutputStream();
try {
//将输入输出管道流连接
in.connect(out);
//将管道流添加到多线程中
Read r = new Read(in);
Writer w = new Writer(out);
//创建线程
Thread tr = new Thread(r);
Thread tw = new Thread(w);
//开启线程
tr.start();
tw.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Read implements Runnable{
private PipedInputStream pipIn;
//通过构造函数传入PipedInputStream对象
public Read(PipedInputStream pipIn){
this.pipIn = pipIn;
}
public void run() {
try {
//读取数据
byte[] buf = new byte[1024];
int len = pipIn.read(buf);
String s = "没有数据";
if(len!=-1){
s = new String(buf,0,len);
}
System.out.println(s);
} catch (IOException e) {
throw new RuntimeException("管道流读取失败");
}finally{
if(pipIn!=null){
try {
pipIn.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
class Writer implements Runnable{
private PipedOutputStream pipOut;
public Writer(PipedOutputStream pipOut){
this.pipOut = pipOut;
}
public void run() {
try {
//写入数据
pipOut.write("管道TEST".getBytes());
} catch (IOException e) {
throw new RuntimeException("管道流输出失败");
}finally{
if(pipOut!=null){
try {
pipOut.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
3. RandomAccessFile
package io;
import java.io.IOException;
import java.io.RandomAccessFile;
/*
* RandomAccessFile
*
* 该类不是IO体系中的子类,而是直接继承自Object
* 既能读又能写,封装了数组和指针
*
* 但是他是IO包中的成员,因为它具备读和写功能,内部封装了一个数组,而且通过指针对数组中的元素进行操作
* 可以通过getFilePointer获取指针位置,同时通过seek改变指针的位置
*
* 内部封装了字节输入输出流,该类只能操作文件,并且还有操作模式:只读"r" 读写"rw"
* 如果模式为"r",不会创建文件,只读取已存在的文件,如果文件不存在,则出现异常。
* 如果模式为"rw",操作文件不存在,会自动创建文件。
*/
public class RandomAccessFileDemo {
public static void main(String[] args) {
String dir = "E:\\BaiduYunDownload\\FILE";
try {
writeFile(dir);
System.out.println("数据已输出");
readFile(dir);
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeFile(String dir) throws IOException{
//创建RandomAccessFile对象,设置读写模式
RandomAccessFile raf = new RandomAccessFile(dir+"\\raf.txt", "rw");
//写入
raf.write("张三".getBytes());
raf.writeInt(65);
raf.write("李四".getBytes());
raf.writeInt(97);
raf.close();
}
private static void readFile(String dir) throws IOException{
RandomAccessFile raf = new RandomAccessFile(dir+"\\raf.txt", "r");
//调整指针
raf.seek(4*2);
//读取四个字节
byte[] buf = new byte[4];
int len = raf.read(buf);
String s = "";
if(len!=-1){
s = new String(buf,0,len);
}
System.out.println(s);
raf.close();
}
}
4. DataInputStream 和 DataOutputStream
package io;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
/*
* 用于操作基本类型的数据流对象
*/
public class DataStreamDemo {
public static void main(String[] args) {
String dir = "E:\\BaiduYunDownload\\FILE";
try {
writeDataUTF(dir);
// readData(dir);
//用转换流的方法,输出utf-8编码的字符流
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(new File(dir+"\\osw.txt")),"utf-8");
osw.write("测试");
osw.close();
readDataUTF(dir);
System.out.println("完成");
} catch (IOException e) {
e.printStackTrace();
}
}
//使用utf-8改版字符码表来输出数据,输出后只能使用readUTF()来读取
private static void writeDataUTF(String dir) throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream(dir+"\\dosUTF.txt"));
dos.writeUTF("测试");
dos.close();
}
//使用utf-8改版字符码表来读取数据
private static void readDataUTF(String dir) throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream(dir+"\\dosUTF.txt"));
String s = dis.readUTF();
System.out.println("字符串:"+s);
dis.close();
}
//输出基本类型数据
private static void writeData(String dir) throws IOException{
DataOutputStream dos = new DataOutputStream(new FileOutputStream(dir+"\\dos.txt"));
dos.writeInt(423);
dos.writeBoolean(true);
dos.writeDouble(11.22);
dos.close();
}
//按着顺序读取基本数据类型数据
private static void readData(String dir) throws IOException{
DataInputStream dis = new DataInputStream(new FileInputStream(dir+"\\dos.txt"));
int num = dis.readInt();
boolean b = dis.readBoolean();
double d = dis.readDouble();
System.out.println("数字:"+num+"\n"+"布尔:"+b+"\n"+"小数:"+d+"\n");
dis.close();
}
}
5. ByteArrayInputStream 和 ByteArrayOutputStream
package io;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/*
* 用于操作字节数组的流对象
*
* ByteArrayInputStream:构造时需要接收数据源,而且数据源是一个字节数组。
* ByteArrayInputStream:构造时不需要定义数据源,而是在内部封装了一个可变长度的字节数组。
*
* 因为两个流对象都操作数组,并没有使用系统资源,所以不用关闭。
*
* 跟它类似的还有: 字符数组流CharArrayReader、ChararrayWriter
* 字符串流 StringReader、StringWriter
*/
public class ByteArrayStreamDome {
public static void main(String[] args) {
//数据源
byte[] buf = "ABCDEFG".getBytes();
ByteArrayInputStream in = new ByteArrayInputStream(buf);
//数据目的
ByteArrayOutputStream out = new ByteArrayOutputStream();
int len = 0;
while((len=in.read())!=-1){
out.write(len);
}
System.out.println(out.toString());
}
}