最近,在看一下OpenOffice的一些资料,openoffice使用XML作为文档的存储格式,一个ODT文件实际上是一个标准的zip文件,其中主要包括:
- meta-inf/manifest.xml 描述zip文件中的每一个文件及其mime类型
- content.xml 主文档内容,
- styles.xml 文档中的样式表。在content.xml中没有存储字体、颜色等信息,这些全部通过style来引用在此中定义的格式。
- meta.xml 文档的主要元信息,如作者、keywords等
- setting.xml 一些设置信息,例如打印设置、显示设置等。
其中最为主要的应该是content.xml和styles.xml了。这些XML都由oasis组织负责进行规范定义,因此,openoffice的文档格式是存在定义良好的标准的,这也为其进一步的发展提供了很好的基础。
我在分析OpenDocument-v1.0-os.sxw(就是OASIS对OpenOffice文档XML定义的文档)进行分析时,发现:这个sxw 文档大小为434K,content.xml文件大小为:4.58m, 整个文档长达706页。把这个文档另存为Word文档在MS Office2003中打开时,文件大小变为3.86M,压缩后为607K。在性能上,OpenOffice打开此文档大约需要6s时间,CPU及内存消 耗很小,而word打开此文档的时间相当长,内存耗费巨大,而且,在后续的操作过程中,反映非常的慢,动不动就CPU紧张,虽然我的机器有1G的ram, 但可用性大大降低。
那么究竟是什么原因让openoffice在处理大文档时具有如此好的性能呢?我没有研究openoffice的源代码,不知道其内部的结构和处理逻辑, 因此,这里的一些想法纯粹是我个人的一些想法。就是说,如果让我来设计,应该如何才能使用很小的内存开销,但又能够快速的对文件进行处理呢?
Level1: fragged - (compressed)- xml -stream :用来存储XML的字节流,采用分块的方式,每一块保存XML的一部分。Level 1 提供了对XML的随机访问的能力。由于实际上,大部分的XML操作都是在一个区域内进行,因此,提供随机访问的能力,将使得XML处理更为方便。
采用分块的形式进行存储,通过算法进行调整,每一块的大小尽可能平衡。当块不经常访问时,整个快可以被压缩。而当块需要随机访问时,又可以解压缩。 Level1 实际上比较适合于作为一种中间存储格式,在文档编辑的过程中,经常需要保存当前的快照,如果每次都保存成zip-xml的话,效率会很低。
Level 2: Lazy DOM:在Level1的基础之上,构建整个文档的DOM。建议采用类似于JDOM的DOM结构(不再处理一些XML的语法甜品,如CDATA、 &扩展等),不过Lazy DOM中的每一个节点并不完整的构建出整个的DOM在内存中,而是根据需要创建DOM节点,在不需要时,自动的进行垃圾回收。(如果我们可以进一步自己的 管理对象的内存,例如重用旧的对象的话,可能效果会更好)。由于在文档浏览、编辑过陈各种,总是在一个较小的活动区域内进行,因此,Lazy DOM将使得我们无须尽力整个的DOM,而尽可能的使用更小的内存。
Level 3: Application Object Model:DOM是完全面向XML的,优势是天然的XML一致,几乎没有距离,不会损失XML信息(但我们还是会做出一些XML的限制,例如不使用 CDATA、&替换等),但不便于进行应用处理。在OO的世界中,我们应该提供一个AOM层,将DOM映射成为应用的对象。JAXB2 是一种候选的技术,但我们仍然希望 AOM 能够与 DOM 相结合使用。建立在LazyDOM的基础之上,整个AOM也可以是Lazy的。从而仅按需创建AOM对象。
Level 4: Cached Runtime Object。以Writer文档为例,如果只基于Lazy AOM,那么,当处理用户需要调准到第#页时,或者跳转到第#章时,是否需要激活整个DOM,来发现第#页的信息呢?如果是这样的话,一定会影响效率的。 如果我们可以预先计算所有的Page,把Page的信息Cache起来(但是在Cache中不应该直接引用DOM,而应该是一个Ref,这个Ref并不防 止相应的DOM可以Lazy化,但又可以在需要的时候对其激活,并且最佳的实现API级的透明化),那么,在处理这种操作时,我们可以直接从该Page对 象出发,显示此页面。这里的一个关键的技术是透明化的访问和DOM对象的Reference技术。(从sxw文件的存储来看,其中包括一个layout- cache的二进制文件,应该就是做这个用途的)
以上面例子来看,一个4.58M的Content.xml,假设:
1、fragged-stream 大约为1M(或者干脆使用不压缩的格式,但存储在磁盘中,并不占用内存)
2、Lazy DOM:一般的,一个文档的活动DOM集大约在512K-1M的范围。
3、AOM:跟LazyDOM类似。
4、其他:可以跟据需要,一般是一个相对估计的内存开销,大约1-2M。
也就是说,理论上,我们只需要4-5M的ram,就可以进行一个如此巨大的文档的编辑活动了。
一个比较好的试验方式是:使用Java做一个模拟性的开发,以展示为主题,然后逐步过渡到编辑工具上,说不定可以成就一个JavaOffice呢。说实在的,Java世界真的需要这样的一个Office,而Office移植到Java也一定有更好的前途。