1. 压缩
CheckedInputStream: GetCheckSum()为任何InputStream()产生校验和。
CheckOutputStream: GetCheckSum()为任何OutputStream产生校验和。
DeflaterOutputStream: 压缩类的基类。
ZipOutputStream: 一个DeflaterOutputStream,用于将数据压缩成Zip文件格式。
GZIPOutputStream: 一个DeflaterOutputStream,用于将数据压缩成GZIP文件格式。
DeflaterInputStream: 解压缩类的基类。
ZipInputStream: 一个DeflaterInputStream,用于解压缩Zip文件格式。
GZIPInputStream: 一个DeflaterInputStream,用于解压缩GZIP文件格式。
2. Serializable
Java的对象序列化将那些实现了Serializable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象。
这一过程甚至可以通过网络进行,这意味着序列化机制能自动弥补不同操作系统之间的差异。
对象序列化主要有两种特性:一是Java远程调用。使存活于其他计算机上的对象使用起来就像存活于本机上一样,当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。
二是JavaBeans序列化配置。
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Random;
class Data implements Serializable{
private int n;
public Data(int n){
this.n=n;
}
public String toString(){
return Integer.toString(n);
}
}
public class Worm implements Serializable {
private static Random rand = new Random(47);
private Data[] d = {new Data(rand.nextInt(10)),new Data(rand.nextInt(10)),new Data(rand.nextInt(10))};
private Worm next;
private char c;
public Worm(){
System.out.println("Default constructor");
}
public Worm(int i, char x){
System.out.println("Worm constructor: "+i);
c=x;
if(--i>0)
next = new Worm(i, (char)(x+1));
}
public String toString(){
StringBuffer result = new StringBuffer();
result.append(c);
result.append("(");
for(Data data:d){
result.append(data);
}
result.append(")");
if(next!=null){
result.append(next);
}
return result.toString();
}
public static void main(String[] args) throws Exception, IOException {
Worm w = new Worm(6,'a');
System.out.println("w="+w);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
out.writeObject("Worm storage\n");
out.writeObject(w);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
String s = (String) in.readObject();
Worm w2 = (Worm) in.readObject();
System.out.println(s+"w2="+w2);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out2 = new ObjectOutputStream(bout);
out2.writeObject("Worm storage\n");
out2.writeObject(w);
out2.flush();
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
s=(String) in2.readObject();
Worm w3 = (Worm) in2.readObject();
System.out.println(s+"w3="+w3);
}
}
//*Output:
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w=a(853)b(119)c(802)d(788)e(199)f(881)
Worm storage
w2=a(853)b(119)c(802)d(788)e(199)f(881)
Worm storage
w3=a(853)b(119)c(802)d(788)e(199)f(881)
*//
对一个Serializable还原中,没有调用任何构造器包括默认构造器,整个对象都是从InputStream中取得数据恢复而来。
Serializable恢复,需要寻找相关的类:
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class FreezeAlien {
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("X.flie"));
Alien quellek = new Alien();
out.writeObject(quellek);
}
}
class Alien implements Serializable{}
//: ../ThawAlien.java
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
public class ThawAlien {
public static void main(String[] args) throws IOException, Exception {
// TODO Auto-generated method stub
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File("..", "X.flie")));
Object o = in.readObject();
System.out.println(o.getClass());
}
}
打开文件和读取mystery对象中的内容都要需要Alien的Class对象;而Java虚拟机找不到Alien.class,必须保证JVM能找到相关.class文件。
2.1 序列化控制
Externalizable代替Serializable进行序列化控制。Externalizble接口继承Serializable,并添加writeExternal()和readExternal(),这两个方法在序列化和反序列化还原过程中被自动调用。
import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
class Blip1 implements Externalizable{
public Blip1(){
System.out.println("Blip1 Con");
}
@Override
public void readExternal(ObjectInput arg0) throws IOException,
ClassNotFoundException {
System.out.println("Blip1 readExternal");
}
@Override
public void writeExternal(ObjectOutput arg0) throws IOException {
System.out.println("Blip1 writeExternal");
}
}
class Blip2 implements Externalizable{
Blip2(){
System.out.println("Blip2 Con");
}
@Override
public void readExternal(ObjectInput arg0) throws IOException,
ClassNotFoundException {
System.out.println("Blip2 readExternal");
}
@Override
public void writeExternal(ObjectOutput arg0) throws IOException {
System.out.println("Blip2 writeExternal");
}
}
public class Blips {
public static void main(String[] args) throws IOException, Exception {
System.out.println("Constructing Objects:");
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Blips.out"));
System.out.println("Saving Objects:");
o.writeObject(b1);
o.writeObject(b2);
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blips.out"));
System.out.println("Recovering b1:");
b1 = (Blip1) in.readObject();
System.out.println("Recovering b2:");
b2 = (Blip2) in.readObject();
}
}
//*Output:
Constructing Objects:
Blip1 Con
Blip2 Con
Saving Objects:
Blip1 writeExternal
Blip2 writeExternal
Recovering b1:
Blip1 Con
Blip1 readExternal
Recovering b2:
Exception in thread "main" java.io.InvalidClassException: com.ld.tij.xfiles.Blip2; com.ld.tij.xfiles.Blip2; no valid constructor
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.ld.tij.xfiles.Blips.main(Blips.java:63)
//
因为Blip2构造器不是公有,在恢复Bilp2时候出现异常。
恢复Serializable对象时,对象完全以存储二进制为基础来构造,而不是构造器。
而Externalizable所有普通默认构造器都会被调用,然后调用readExternal()。
transient关键字
某个特定子对象不想让Java序列化自动保存与恢复。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
public Logon(String name, String pwd){
this.username=name;
this.password=pwd;
}
public String toString(){
return "logon info: \n username: "+username+"\n date: "+date+"\n password: "+password;
}
public static void main(String[] args) throws IOException, Exception {
Logon a = new Logon("Dog", "lucky");
System.out.println("Logon a="+a);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
o.writeObject(a);
o.close();
TimeUnit.SECONDS.sleep(1);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
System.out.println("Recovering objec at "+ new Date());
a=(Logon) in.readObject();
System.out.println("logon a="+a);
}
}
//*Output:
Logon a=logon info:
username: Dog
date: Mon Oct 21 10:51:51 CST 2013
password: lucky
Recovering objec at Mon Oct 21 10:51:52 CST 2013
logon a=logon info:
username: Dog
date: Mon Oct 21 10:51:51 CST 2013
password: null
//
Serializable还有一种办法是添加writeObject()和readObject()方法,这样对象一旦被序列化或者反序列化都会自动调用这两个方法。
如果是Externalizable,可以在writeExternal()内部只对需要部分进行序列化即可。
2.2 持久性
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
class House implements Serializable{}
class Animal implements Serializable{
private String name;
private House house;
Animal(String n, House h){
name=n;
house=h;
}
public String toString(){
return name+"["+super.toString()+"], "+house+"\n";
}
}
public class MyWorld {
public static void main(String[] args) throws Exception {
House house = new House();
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Animal("Bosco the dog", house));
animals.add(new Animal("Ralph the hamster", house));
animals.add(new Animal("Molly the cat", house));
System.out.println("animals: "+animals);
ByteArrayOutputStream buf1 = new ByteArrayOutputStream();
ObjectOutputStream o1 = new ObjectOutputStream(buf1);
o1.writeObject(animals);
o1.writeObject(animals);
ByteArrayOutputStream buf2 = new ByteArrayOutputStream();
ObjectOutputStream o2 = new ObjectOutputStream(buf2);
o2.writeObject(animals);
ObjectInputStream in1 = new ObjectInputStream(new ByteArrayInputStream(buf1.toByteArray()));
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(buf2.toByteArray()));
List animal1 = (List) in1.readObject();
List animal2 = (List) in1.readObject();
List animal3 = (List) in2.readObject();
System.out.println("animal1: "+animal1);
System.out.println("animal2: "+animal2);
System.out.println("animal3: "+animal3);
}
}
//*Output:
animals: [Bosco the dog[com.ld.tij.Animal@3d4b7453], com.ld.tij.House@24c21495
, Ralph the hamster[com.ld.tij.Animal@41d5550d], com.ld.tij.House@24c21495
, Molly the cat[com.ld.tij.Animal@1cc2ea3f], com.ld.tij.House@24c21495
]
animal1: [Bosco the dog[com.ld.tij.Animal@28df8ff1], com.ld.tij.House@6d632c2d
, Ralph the hamster[com.ld.tij.Animal@9e97676], com.ld.tij.House@6d632c2d
, Molly the cat[com.ld.tij.Animal@3e60420f], com.ld.tij.House@6d632c2d
]
animal2: [Bosco the dog[com.ld.tij.Animal@28df8ff1], com.ld.tij.House@6d632c2d
, Ralph the hamster[com.ld.tij.Animal@9e97676], com.ld.tij.House@6d632c2d
, Molly the cat[com.ld.tij.Animal@3e60420f], com.ld.tij.House@6d632c2d
]
animal3: [Bosco the dog[com.ld.tij.Animal@219106c7], com.ld.tij.House@38540408
, Ralph the hamster[com.ld.tij.Animal@13d4c61c], com.ld.tij.House@38540408
, Molly the cat[com.ld.tij.Animal@761a626f], com.ld.tij.House@38540408
]
*//
这个例子中,Animal对象包含House类型字段,在main方法中创建一个Animal列表并将其两次序列化,分别推送到不同的流中。
当其被反序列化还原打印时,我们期望反序列化后对象地址与原来不同,但是animal1和animal2地址却相同,包括二者共享House对象的引用。
而恢复animal3时,系统无法知道另一个流内的对象是第一个流内对象的别名,因此产生完全不同的对象网。
如果想保存系统状态,最安全的做法是将其作为 原子 操作进行序列化。 如果我们序列化了某些东西,再去做其他工作,然后才序列化,那么将无法安全保存系统状态。正确的做法应该是:将保存系统状态的所有对象都放在一个单一容器,一个操作中将其直接写出,然后同样一个操作调用,即可恢复。
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
abstract class Shape implements Serializable{
public static final int RED=1, BULE=2, GREEN=3;
private int xPos, yPos, dimension;
private static Random rand = new Random(47);
private static int counter=0;
public abstract void setColor(int newColor);
public abstract int getColor();
public Shape(int xVal, int yVal, int dim){
xPos=xVal;
yPos=yVal;
dimension=dim;
}
public String toString(){
return getClass() + "color["+getColor()+"] xPos["+xPos+"] yPos["+yPos+"] dim["+dimension+"]\n";
}
public static Shape randomFactory(){
int xVal = rand.nextInt(100);
int yVal = rand.nextInt(100);
int dim = rand.nextInt(100);
switch(counter++%3){
default:
case 0:return new Circle(xVal,yVal,dim);
case 1:return new Square(xVal,yVal,dim);
case 2:return new Line(xVal,yVal,dim);
}
}
}
class Circle extends Shape{
private static int color = RED;
public Circle(int xVal, int yVal, int dim){
super(xVal,yVal,dim);
}
public void setColor(int newColor){
color = newColor;
}
public int getColor(){
return color;
}
}
class Square extends Shape{
private static int color;
public Square(int xVal, int yVal, int dim){
super(xVal,yVal,dim);
color = RED;
}
public void setColor(int newColor){
color = newColor;
}
public int getColor(){
return color;
}
}
class Line extends Shape{
private static int color = RED;
public static void serializeStaticState(ObjectOutputStream os) throws IOException{
os.writeInt(color);
}
public static void deserializeStaticState(ObjectInputStream os) throws IOException{
color = os.readInt();
}
public Line(int xVal, int yVal, int dim){
super(xVal,yVal,dim);
}
public void setColor(int newColor){
color = newColor;
}
public int getColor(){
return color;
}
}
public class StoreCADState {
public static void main(String[] args) throws IOException {
List<Class<? extends Shape>> shapeTypes = new ArrayList<Class<? extends Shape>>();
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
List<Shape> shapes = new ArrayList<Shape>();
for(int i=0;i<10;i++){
shapes.add(Shape.randomFactory());
}
for(int i=0;i<10;i++){
((Shape)shapes.get(i)).setColor(Shape.GREEN);
}
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("CADState.out"));
out.writeObject(shapeTypes);
Line.serializeStaticState(out);
out.writeObject(shapes);
System.out.println(shapes);
}
}
//*Output
[class com.ld.tij.Circlecolor[3] xPos[58] yPos[55] dim[93]
, class com.ld.tij.Squarecolor[3] xPos[61] yPos[61] dim[29]
, class com.ld.tij.Linecolor[3] xPos[68] yPos[0] dim[22]
, class com.ld.tij.Circlecolor[3] xPos[7] yPos[88] dim[28]
, class com.ld.tij.Squarecolor[3] xPos[51] yPos[89] dim[9]
, class com.ld.tij.Linecolor[3] xPos[78] yPos[98] dim[61]
, class com.ld.tij.Circlecolor[3] xPos[20] yPos[58] dim[16]
, class com.ld.tij.Squarecolor[3] xPos[40] yPos[11] dim[22]
, class com.ld.tij.Linecolor[3] xPos[4] yPos[83] dim[6]
, class com.ld.tij.Circlecolor[3] xPos[75] yPos[10] dim[42]
]
*//
恢复对象:
import java.io.*;
import java.util.*;
public class RecoverCADState {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws Exception {
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("CADState.out"));
// Read in the same order they were written:
List<Class<? extends Shape>> shapeTypes =
(List<Class<? extends Shape>>)in.readObject();
Line.deserializeStaticState(in);
List<Shape> shapes = (List<Shape>)in.readObject();
System.out.println(shapes);
}
}
//*Output:
[class com.ld.tij.Circlecolor[1] xPos[58] yPos[55] dim[93]
, class com.ld.tij.Squarecolor[0] xPos[61] yPos[61] dim[29]
, class com.ld.tij.Linecolor[3] xPos[68] yPos[0] dim[22]
, class com.ld.tij.Circlecolor[1] xPos[7] yPos[88] dim[28]
, class com.ld.tij.Squarecolor[0] xPos[51] yPos[89] dim[9]
, class com.ld.tij.Linecolor[3] xPos[78] yPos[98] dim[61]
, class com.ld.tij.Circlecolor[1] xPos[20] yPos[58] dim[16]
, class com.ld.tij.Squarecolor[0] xPos[40] yPos[11] dim[22]
, class com.ld.tij.Linecolor[3] xPos[4] yPos[83] dim[6]
, class com.ld.tij.Circlecolor[1] xPos[75] yPos[10] dim[42]
]
*//
可以看到,xPos, yPox, dim的值都被成功保存和恢复,但是static却出现了问题,所有恢复的static都应该是3,只有Line的color恢复正确。
Line中serializeStaticState()和deserializeStaticState()两个方法作为存储和读取过程的一部分被显示的调用。
以上例子正确修改方式:
1)为其他几何图形添加serializeStaticState()和deserializeStaticState()两个方法。
2)移除ArrayList shapeTypes相关代码。
3)添加对几何图形新的序列化和反序列化的显示调用。
因为序列化也会对private保存下来,如果是涉及安全问题还需要标记transient。
IO End~:)