首页 > 学院 > 开发设计 > 正文

zip文档和对象流与序列化

2019-11-14 10:37:19
字体:
来源:转载
供稿:网友

Zip文档(通常)以压缩格式存储了一个或多个文件,每个ZIP文档都有一个包含诸如文件名字和所使用的压缩方法等信息的头。在java中,可以使用ZipInputStream来读入ZIP文档。你可能需要浏览文档中每个单独的项, getNextEntry方法就可以返回一个描述这些项的ZipEntry类型的对象。 ZipInputStream的read方法被修改为在碰到当前项的结尾时返回-1(而不是碰到ZIP文件的末尾),然后你必须调用closeEntry来读入下一项。

		ZipInputStream z = new ZipInputStream(new FileInputStream("zip"));		ZipEntry zip;		while((zip=z.getNextEntry())!=null){			//读取内容,用Scanner或者reader			z.closeEntry();//读取下一个		}		z.close();ZIP输入流在读入ZIP文件发生错误时,会抛出ZipException。通常这种错误在ZIP文件被破坏时发生。要写出到ZIP文件,可以使用ZipOutputStream,而对于你希望放入到ZIP文件中的每一项,都应该创建一个ZipEntry对象,并将文件名传递给ZipEntry的构造器,它将设置其他诸如文件日期和解压缩方法等参数。如果需要,你可以覆盖这些设置。然后,你需要调用ZipOutputStream的putNextEntry方法来开始写出新文件,并将文件数据发送到ZIP流中。当完成时,需要调用closeEntry。然后,你需要对所有你希望存储的文件都重复这个过程。下面是代码框架:
		ZipOutputStream z = new ZipOutputStream(new FileOutputStream("f://a.zip"));		ZipEntry ze = new ZipEntry("wwww.txt");//文件名		z.putNextEntry(ze);		z.write(123);		z.write(123);		z.closeEntry();//重复上面的操作来写多个文件		z.close();JAR文件(在第I卷第10章中讨论过)只是带有另一个项的ZIP文件,这个项称作清单。你可以使用JarInputStream和JarOutputStream类来读写清单项。ZIP流是一个能够展示流的抽象化的强大之处的实例。当你读入以压缩格式存储的数据时,不必操心边请求边解压数据。而且ZIP格式的字节源并非必须是文件,也可以是来自网络连接的ZIP数据。事实上,只要Applet的类加载器能够读入JAR文件,那么它就能够读入和解压来自网络的数据。

对象流与序列化

当你需要存储相同类型的数据时,使用固定长度的记录格式是一个不错的选择。但是,在面向对象程序中创建的对象很少全部都具有相同的类型Java语言支持一种称为对象序列化( object serialization)的非常通用的机制,它可以将任何对象写出到流中,并在之后将其读回。为了保存对象数据,首先需要打开一个ObjectOutputStream对象:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f://f.txt"));
oos.writeObject(new String(xxxx));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f://f.txt"));ois.readObject();但是,你必须对希望在对象流中存储或恢复的所有类都进行一下修改,这些类必须实现Serializable接口。Serializable接口没有任何方法,因此你不需要对这些做任何改动。Cloneable接口很相似。但是,为了使类可克隆,你仍旧需要覆盖Object类中的clone方法。

你只有在写出对象时才能用writeObject/readObject方法,对于基本类型值,你需要使用诸如writeInt/readInt或writeDouble/readDouble这样的方法。(对象流类都实现了DataInput/DataOutput接口。)当一个对象被多个对象共享,作为它们各自状态的一部分时。保存会有问题所以就要序列化。每个对象都是用一个序列号( serial number)保存的,这就是这种机制之所以称为对象序列化的原因。

比如有两个对象共用一个相同的对象,把这两个对象保存的流中就会有问题。不能去保存和恢复相同对象的地址,因为当对象被重新加载时,它可能占据的是与原来完全不同的内存地址。所以要序列化。

1.对你遇到的每一个对象引用都关联一个序列号。2.对于每个对象,当第一次遇到时,保存其对象数据到流中。3.如果某个对象之前已经被保存过,那么只写出“与之前保存过的序列号为x的对象相同”。在读回对象时,整个过程是反过来的。4.对于流中的对象,在第一次遇到其序列号时,构建它,并使用流中数据来初始化它,然后记录这个顺序号和新对象之间的关联。5.当遇到“与之前保存过的序列号为x的对象相同”标记时,获取与这个顺序号相关联的对象引用。使用序列化将对象集合保存到磁盘文件中,并按照它们被存储的样子获取它们。序列化的另一种非常重要的应用是通过网络将对象集合传送到另一台计算机上。正如在文件中保存原生的内存地址毫无意义一样,它们对于在不同的处理器之间的通信也是毫无意义的。因为序列化用序列号代替了内存地址,所以它允许将对象集合从一台机器传送到另一台机器。transient关键字加上就不会被序列化。除了让序列化机制来保存和恢复对象数据,类还可以定义它自己的机制。为了做到这一点,这个类必须实现Externalizable接口。如果一个类具有名为serialVersionUID的静态数字成员, 它就不需要再人工地计算其指纹,而只需直接使用这个值。一旦这个静态数据成员被置于某个类的内部,那么序列化系统将可以读入这个类的对象的不同版本。如果数据域产生了变化,对象流将尽力将流对象转换成这个类当前的版本。对象流会将这个类当前版本的数据域与流中版本的数据域进行比较,当然,对象流只会考虑非瞬时和非静态的数据域。如果这两部分数据域之间名字匹配而类型不匹配,那么对象流不会尝试将一种类型转换成另一种类型,因为这两个对象不兼容;如果流中的对象具有在当前版本中所没有的数据域,那么对象流会忽略这些额外的数据;如果当前版本具有在流化对象中所没有的数据域,那么这些新添加的域将被设置成它们的默认值(如果是对象则是null,如果是数字则为0,如果是boolean值则是false)序列化机制有一种很有趣的用法:它提供了一种克隆对象的简便途径,只要对应的类是可序列化的即可。其做法很简单:直接将对象序列化到输出流中,然后将其读回。这样产生的新对象是对现有对象的一个深拷贝( deep copy)。在此过程中,我们不必将对象写出到文件中,因为可以用ByteArrayOutputStream将数据保存到字节数组中。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表