作为项目文件格式,替代ZIP的选择:SQLite 还是其他?

3
我的Java应用程序目前使用ZIP作为项目文件格式。项目文件包含几个XML文件和许多图像和声音文件。
项目文件变得相当大,由于我找不到java.util.zip类的方法来在不重新创建ZIP文件的情况下写入ZIP文件,因此我的文件保存变得非常缓慢。例如,如果我只想更新一个XML文件,我需要重写整个ZIP文件。
是否有其他Java ZIP库可以允许我对ZIP文件进行随机写入?
我知道切换到像SQLite这样的东西可以解决随机写入问题。将XML、声音和图像作为blob写入SQLite是否是适当的用法?
我想我可以想出自己的文件格式并使用RandomAccessFile,但那将需要我编写很多簿记。
更新...
我的文件格式非常像Office Open XML。它是一个包含XML和其他资源的ZIP文件。
肯定有人解决了如何进行随机写以更新ZIP文件的问题。有人知道怎么做吗?

1
我的Java应用程序目前使用ZIP作为项目文件格式。 JAR文件会更合适吧? - Powerlord
有没有一种方法可以随机写入一个与ZIP不同的JAR文件? - awinbra
3
JAR 实际上是一个带有元数据的 ZIP 文件。在性能方面与 ZIP 没有任何区别。 - Eugene Mayevski 'Callback
5个回答

3

存在所谓的单文件虚拟文件系统,它允许您创建基于文件的容器并提供类似文件系统的结构和API。其中一个示例是SolFS(它具有C编写的核心和JNI包装器)以及其他一些C和Delphi编写的解决方案(我暂时不记得它们的名称)。我猜想也存在类似的本地Java解决方案。


一个虚拟文件系统可能是一个不错的方向。我发现了TrueZip,它声称是一个用于ZIP的Java虚拟文件系统。如果它真的可以随机写入ZIP文件,那么这将是一个完美的解决方案。我会进一步调查。 - awinbra
我想我理解了你的问题。Java内置的ZIP类不支持修改现有存档(即没有AddEntry/DeleteEntry方法),而trueZip正好填补了这个空白(这个空白是特定于ZIP访问代码的实现)。然而,无论使用哪个库或组件,这都不是真正的虚拟文件系统,因为ZIP格式本身并不打算在这种情况下使用。当ZIP文件被修改时,无论使用什么库或组件,这仍然是一个漫长而耗时的操作。待续... - Eugene Mayevski 'Callback
相反,“真实”的虚拟文件系统操作页面(类似于物理磁盘上的簇),添加和删除文件不需要对文件进行重写(在底层或显式地)。只有修改过的页面才会被就地覆盖。使用TrueZip创建一个巨大的文件,并尝试删除或修改文件中间的条目,然后测量速度。 - Eugene Mayevski 'Callback
感谢您的回复。我将进一步研究使用VFS。我发现了ZX-VFS - http://www.zipxap.com/HomePage_Products_ZxVfs.html,它看起来正是我需要的。但是关于这个产品的信息非常少。它似乎很新。 - awinbra

2
首先,我建议将您的应用程序资源分为静态资源(例如图像)和可更改资源(您提到的xml文件)两类。由于静态文件不会被重写,因此您可以继续将它们存储在zip文件中,这是部署任何资源的良好方法。
现在您有两个选择:
1. 由于非静态文件可能不太大(xml文件可能比图像+声音小),因此您可以继续使用当前解决方案(zip文件),并仅维护2个zip文件,其中只有一个(包含可更改文件的较小文件)可以/将被重新编写。
2. 您可以使用内存数据库(例如hsqldb)来存储可更改文件,并且只有在应用程序关闭或明确需要该操作时才将它们持久化(从数据库转移到驱动器上的文件)。

我需要将所有东西放在一个项目文件中。 - awinbra

1

在我的经验中,sqlite并不总是快速的。我建议单独压缩XML文件--你仍然可以得到不错的压缩效果,并使用文件系统来保存它们。你可以尝试使用btrfs,或者选择ext4。如果你不在Linux上,那么这个方法仍然可以正常工作,但在内存缓存之前可能不会很快。

这个想法是,如果你的XML文件之间没有冗余,那么将它们压缩成一个“实心”归档文件并不能节省太多空间。


ZIP 的目标不是压缩 XML,而是将所有项目文件组合成一个单独的文件。我能用 btrfs 来做到这一点吗? - awinbra
不好意思,我建议不要将文件分组。你为什么想这样做?在Linux中,您可以使用任何常规文件作为整个文件系统--只需运行类似于“dd if=/dev/zero of=file1 bs=1M count=100; /sbin/mkfs.ext4 file1; mkdir -p mountpoint; sudo mount file1 mountpoint -o loop”的命令,您写入“mountpoint/”目录中的所有内容都将被写入“file1”中--您可以通过“md5sum file1; echo > mountpoint/asdf; sync; md5sum file1”来观察到这一点。 - gatoatigrado
我忘记添加了 - Mac 通过 .dmg 提供了相同功能的非常好的支持。 - gatoatigrado

1
在提供另一种使用正确结构的JAR文件的答案之前,我必须问一下——为什么项目需要封装在一个文件中?你是如何将程序分发给用户运行的?

这是一个桌面应用程序,用户可以下载和安装。他们使用它的方式很像用户使用PowerPoint。他们创建包含媒体文件的项目并分享这些项目。 - awinbra

1

如果您必须将项目保存在单个文件中并且能够有效地替换资源,那么我会说SQLite是一个不错的选择。

如果您选择使用SQLite,请考虑将一些XML模式转换为一个或多个SQL表,而不是将大型XML文档存储为BLOB。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接