在转载之前,有一些第三方的jar包是必须导入的:????
xstream-1.4.1.jar --必须的
kxml2-2.3.0.jar???? --如果没有这个的话,在执行PrintWriter instance = new PrintWriter(path);是会抛出异常的
kXML2 is a very fast XML pull-parser implementation
转载:http://www.blogjava.net/zlkn2005/archive/2005/12/16/24240.html
XStream
?
使用 XStream 的初衷
?
研究和使用 XStream 的原因是我在项目中的一个预研。在项目中需要应用到对 XML 文件的管理和配置,因此需要一个能够将对象保存为 XML 的工具库,在这里有多种方法实现,我也研究并进行了比对,比如与 Zeus 工具的比对,与 Java 自身的 XML 工具库的比对等。在这里,我就描述下我的 XStream 学习过程和研究结果。
?
XStream 简单介绍
?
XStream 是一个开源项目,一套简单实用的类库,用于序列化对象与 XML 对象之间的相互转换。将 XML 文件内容解析为一个对象或将一个对象序列化为 XML 文件。
XStream 可以用于 JDK1.3 以上的版本使用,我是在 JDK1.5 下使用它的。
XStream 的相关信息可以到 http://xstream.codehaus.org/ 下查看,它有专门的 JavaDoc ,可以方便的阅读 Xstream 的函数及方法。
XStream 中主要的类为 XStream ,它用于序列化对象与 XML 对象之间的相互转换。简单的使用它就可以解决很多问题。
XStream 中主要的方法也是我用的比较多的是 fromXML() 和 toXML() 。
fromXML 用于从 XML 中将对象解析出来。
toXML 用于将对象序列化为 XML 文件。
在 XStream 中我还使用 HierarchicalStreamWriter , HierarchicalStreamReader , createObjectInputStream() , createObjectOutputStream() ,主要是用于对象的输入输出。
下面我们来研究下 XStream 的工作方式。
?
XStream 的实例――将一个序列化对象转化为 XML 对象。
?
一,创建 XStream 对象。
XStream xstream=new XStream();
用默认构造器构造了一个名为 xstream 的 XStream 的对象。默认构造器所使用 XML 解析库为 Xpp3 库, XPP3 是一种运行效率非常高的 XML 全解析实现。
?
二,创建需要序列化的对象。
比如这个类就叫 PrintUnit 。
构造也比较简单,一个简单的 JavaBean
?????? public class PrintUnit
?????? {
????????????? Private String a;
????????????? Private String b;
????????????? Private String c;
?????????????
????????????? Public PrintUnit(){}
?????????????
????????????? Public setA(String a)
????????????? {
???????????????????? this.a=a;
????????????? }
?
????????????? Public getA()
????????????? {
???????????????????? return a;
????????????? }
?
????????????? Public setB(String b)
????????????? {
???????????????????? this.b=b;
????????????? }
?
????????????? Public getB()
????????????? {
???????????????????? return b;
????????????? }
?
????????????? Public setC(String c)
????????????? {
???????????????????? This.c=c;
????????????? }
?
????????????? Public getC()
????????????? {
???????????????????? Return c;
????????????? }
?????? }
?
在例子中使用这个 JavaBean 。
创建并初始化 PrintUnit 。
PrintUnit pu=new PrintUnit();
pu.setA("A11");
pu.setB("B22");
pu.setC("C33");
?
三,创建 Writer 。
创建一个输出流,至于怎么输出我发现可以使用多种方法,其实原理是一样的。
在这里就不得不提到 HierarchicalStreamWriter,HierarchicalStreamWriter 是一个接口,从字面上意思来说它是有等级的输入流。同样在 XStream 中也有不少这个接口的实现类用于输出。我现在所用过的有 CompactWriter 和 PrettyPrintWriter 这 2 个。
我是这样做的:
String str="stream.xml"; // 本目录下的一个名为 stream 的 XML 文件
PrintWriter pw=new PrintWriter(str);// 创建一个 PrintWriter 对象,用于输出。
之后选用一个 HierarchicalStreamWriter 的实现类来创建输出。
选用 CompactWriter 创建:
CompactWriter cw=new CompactWriter(pw);
选用 PrettyPrintWriter 创建:
PrettyPrintWriter ppw=new PrettyPrintWriter(pw);
两者所使用的方法都是很简单的。
CompactWriter 与 PrettyPrintWriter 的区别在于,以 CompactWriter 方法输出的为连续的没有分隔的 XML 文件,而用 PrettyPrintWriter 方法输出的为有分隔有一定格式的 XML 文件。
以 CompactWriter 方式生成的 XML 文件:
?
<object-stream><PrintUnit><a>A11</a><b>B22</b><c>C33</c></PrintUnit></object-stream>
?
以 PrettyPrintWriter 方式生成的 XML 文件:
?????? <object-stream>
? ?????????? <PrintUnit>
?? ???????? ? ???? <a>A11</a>
??? ????????????? <b>B22</b>
??? ????????????? <c>C33</c>
? ?????????? </PrintUnit>
?????? </object-stream>
?
?????? 我想大家能很容易的分辨出它们的差异。
?
?????? 四,输出操作 ??????
以上步骤完成后就可以做输出操作了, XStream 的输出方式有多种: toXML 方式, ObjectOutputStream 方式, marshal 方式以及一些我尚未发现的一些其它方式。
先说下我所使用的方式它们各自的不同点,从工作原理上说它们是相似的,但是做法各不相同。
toXML() 方法,本身 toXML 的方法就有 2 种:
第一种 :java.lang.String toXML(java.lang.Object obj)
将对象序列化为 XML 格式并保存到一个 String 对象中。
第二种 :void toXML(java.lang.Object obj, java.io.Writer out)
将对象序列化为 XML 格式后以 Writer 输出到某个地方存储。
我所使用的是第二种方式,使用前面已经做好的 Pw 就可以实现输出,它其实很简单不需要再去做其它定义,只需要一个 PrintWriter 对象和需要序列化的 Object 即可。
直接调用 xstream.toXML(printUnit,pw); 就能输出 XML 文件 , 在这里是输出到该目录下的 stream.xml 中。这里的输出都是覆盖性的,不是末尾添加形式。
使用 ObjectOutputStream 方式,简单说它就是生成一个对象输出流。
ObjectOutputStream obj_out = xstream.createObjectOutputStream(ppw);
使用 XStream 的 createObjectOutputStream 方法创建一个 ObjectOutputStream 对象,用于 XML 的输出。这里使用的是 PrettyPrintWriter 的方式。 ?? 之后调用 writerObject 方法既可,使用方法与其它输出流类似。
obj_out.writeObject(pu);
obj_out.close();
使用 marshal 方式,其实 marshal 方法和 toXML 方法是相同的。在调用 toXML 方法进行输出时,在 XStream 内部是需要调用 marshal 方法的,然后它再去调用对象 marshallingStrategy 的 marshal 方法。所以做 toXML 其实和 marshal 是相同的,在这里只是想更加说明它的工作方式。
?
使用 void marshal(java.lang.Object obj, HierarchicalStreamWriter writer) 方法。
延续上面的例子,在这里可以这样写: xstream.marshal(pu,ppw);
?
需要注意的是,和 toXML 不同的是参数,一个是 PrintWriter 对象一个则是 PrettyPrintWriter 对象。因为 marshal 中需要
?
HierarchicalStreamWriter ,而 PrettyPrintWriter 则是实现了 HierarchicalStreamWriter 接口的实现类。
?
结果和 toXML 是相同的。
?
五,结果:
?????? <object-stream>
? ?????????? <PrintUnit>
?? ???????? ? ???? <a>A11</a>
? ?? ????????????? <b>B22</b>
??? ????????????? <c>C33</c>
? ?????????? </PrintUnit>
?????? </object-stream>
?
经过以上 5 步的操作既可将一个序列化对象转化为 XML 对象。
?
?
XStream 的实例――将 XML 文件转化为一个对象
?
通过上面的一个例子不难看出 XStream 简便性,既然有了输出就一定会有输入。
输入方我们将会使用 ObjectInputStream 。
与输出相同我们需要有一个 XStream 对象,暂且名为 xstream 。之后需要读取的 XML 文件地址目录信息。沿用上面的例子。
String inputStr="xstream.xml";
XStream xstream=new XStream();
我们需要通过对象流进行输入操作,所以需要 FileReader 和 BufferedReader 。
FileReader fr=new FileReader(inputStr);
BufferedReader br=new BufferedReader(fr);
创建对象输入流
ObjectInputStream obj_input=xstream.createObjectInputStream(br);
创建对象,还是使用 PrintUnit 这个对象。
PrintUnit pu2;
通过 ObjectInputStream 中的 readObject() 方法将对象从 XML 文件中读取出来。
pu2=(PrintUnit)obj_input.readObject();
获取值:
System.out.println(pu2.getB());
控制台:
B22?
?
从整个输入的过程来看,是一个文件的读取,将其中的对象数据取出来,然后再对这个对象数据进行操作。内容也比较简单通过 ObjectInputStream 输入对象。
通过以上的输入输出例子,我想大家应该很容易就能理解 XStream 是如何实现的。
?
FomXML
?
上面使用的是以 ObjectInputStream 的方式进行 XML 与对象之间进行转换的。下面我将使用 XStream 中的 fromXML ()方法进行转换。
首先在使用 fromXML 我发现一个问题,它必须使用正确的解析方式或输出方式对应的输入方式才可以正常解析读取文件,这个问题有点怪,不过确实存在,当我使用前面 ObjectOutputStream 方式输出的 XML 文件 , 用 fromXML ()解析读取时,它会报错。
错误信息:
Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException: object$stream : object$stream
信息内容为:不能解析这个文件。我认为它和输出方式有关,因为上面例子中使用的是 ObjectOutputStream ,当我反过来做了一个实验后也证明了这一点。
实验大致内容:使用 toXML() 方法输出 XML 文件,使用 ObjectInputStream 解析,发现会在读取的时候抛出 CannotResolveClassException 异常。
错误信息:
Exception in thread "main" com.thoughtworks.xstream.alias.CannotResolveClassException:
a : a
?????? 因此我认为在解析文件的时候必须先要确定这个文件是由什么方式生成的,然后在解析它,对于使用 Dom,Dom4j,XPP 等不同方式解析尚未尝试。以上测试是在默认的基础上实验的,默认为 XPP3 的解析器。
?
?????? 使用 fromXML 的方法。
??????
?????? public java.lang.Object fromXML(java.lang.String?xml)
?????? public java.lang.Object fromXML(java.io.Reader?xml)
public java.lang.Object fromXML(java.lang.String?xml,java.lang.Object?root)
public java.lang.Object fromXML(java.io.Reader?xml,java.lang.Object?root)
??????
例子:
?????? PrintUnit puTwo=(PrintUnit)xstream.fromXML(xml);
??????
这里的 xml 必须是使用 toXML() 生成出来的。对于 Reader 没有太多的要求。
?
?
XStream 与 Java.Bean 中 XML 工具的比较
?
?????? XStream 主要作用是将序列化的对象转化为一个 XML 文件或将 XML 文件解析为一个对象。当然并非只有它可以做到,很多其它工具一样可以,在 Java 中存在这样两个类 XMLDecoder 和 XMLEncoder ,它们是在 Java.Bean 包下的,它们的作用是将 JavaBean 转化为 XML 或将 XML 文件转化为一个 Java Bean 。
?????? XMLDecoder 是通过一个输入流将对象从输入流中取出并转化为一个实例的方法。它所需要的就是一个输入流及一个转化过程。
?
?????? XMLDecoder 的实例:
?
?????? String fileStr=”xstream.xml”;//XML 文件,在本目录下,延用上次使用文件。
?????? ObjectInputStream in=new ObjectInputStream(new FileInputStream(fileStr));// 创建一个 ObjectInputStream 用于输入。
?????? XMLDecoder xmld=new XMLDecoder(in);// 创建一个 XMLDecoder 对象。
?????? 延用前面所使用 PrintUnit 这个 Bean 。
?????? PrintUnit pu=(PrintUnit)xmld.readObject();// 通过 XMLDecoder 中的 readObject 方法获得 PrintUnit 对象。
如果获取到了这个对象那么 pu 中将有它的值 a=A11,b=B22,c=C33 。整个过程最好放 try
…catch 中去,能够捕获一些如:文件不存在等异常。
?????? 从操作方式上看 XMLDecoder 似乎不比 XStream 差多少,同样是可以通过 ObjectInputStream 获取 XML 文件中的对象。它们的差异就是解析的方式不同, XMLDecoder 是使用 Java 自带的 XML 解析方式,而 XStream 则是可以自定义的,它可以使用多中方式进行解析。这些是我个人所发现的一些不同点。
?
?????? XMLEncoder 是通过一个输出流将对象序列化并输出为 XML 文件。它所需要的是一个输出流及一个输出方式。
?
?????? XMLEncoder 的实例:
?
?????? String fileStr=”xstream.xml”;// 定义一个输入的目标文件。
?????? ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream(fileStr));// 创建一个对象输出流。
?????? XMLEncoder xmle=new XMLEncoder(out);// 创建一个 XMLEncoder 对象。
?????? 延用前面所使用 PrintUnit 这个 Bean 。
// 创建并初始化 PrintUnit 对象。
PrintUnit pu=new PrintUnit();
pu.setA(“AAA”);
pu.setB(“BBB”);
pu.setC(“CCC”);
?
?????? xmle.writeObject(pu);// 使用 XMLEncode 的 writeObject 方法输出 pu
?????? xmle.flush();// 刷新
?????? xmle.close();// 关闭输出流
?
?????? 从上面的代码不难看出,使用 XMLEncode 方式将对象序列化并输出也是很方便的,简单调用 writeObject 方法能将普通 Bean 输出为 XML 文件。
??????
?????? XML 文件的内容:
?
?_ <? xml version = "1.0" encoding = "UTF-8" ?>
< java version = "1.5.0" class = "java.beans.XMLDecoder" >
? < object class = "test.PrintUnit" >
? < void property = "a" >
?? < string > AAA </ string >
? </ void >
? < void property = "b" >
?? < string > BBB </ string >
? </ void >
? < void property = "c" >
?? < string > CCC </ string >
? </ void >
? </ object >
w?? </java>
?
?????? 不知道是我哪里没有处理,还是实际并不是像我想象的哪么简单,使用 XMLEncoder 所输出的 XML 文件中有一定的问题,虽然它很详细,比起 XStream 所生成的更多,包括了 XML 和 Java 的版本看上去更像是个完整的 XML 文件,不过再细看它们两生成的 XML 格式内容,完全不同,这个我想就是它们最大的区别。这让我想到了很多内容:工作方式,解析器,转换方式等。大家有没发现在开始和结束都存在一些乱码数据,难道在 XMLEncoder 输出过程中或数据转换中内容已经存在“脏”数据了?还是我所使用的输出方式存在问题?哎 … 一个又一个问题出现了。我想我需要再进一步的研究和学习才能得到答案。
?????? 不过尽管有这个那个的问题,使用 Java 本身自带的 XML 工具还是一样很实用的,读取和输出一样可用,操作也很灵活。因此我觉得在某些场合使用特定的工具可能会更好,利用 XMLEncoder 和 XMLDecoder 同样可以解决一些问题。
我的这个使用 XMLDecoder 和 XMLEncoder 的序列化格式输出暂研究到这里。