2

我有一个大小约为 10mb 的 xml 文档。它具有相对简单的结构,但其中包含大量二进制数据。我需要从中获取数据并将其保存在数据库中。尝试过 jaxb metro - 运行速度非常慢。我目前正在为此尝试 jibx,但解组几个 xml 文档会使用所有 jvm 内存 - 堆空间错误 - db 已损坏。也许我应该使用其他东西来阅读 xmls?请给一些建议。

编辑 我的 xml 表示某种消息,其中包含“to”、“from”等信息,只是字符串整数和日期。最大的部分是 byte[] 中的附件,每个附件都有自己的元素。也许可以一一加载?我真的不应该做什么。

4

4 回答 4

2

Unludo 是正确的,您需要使用 STAX 来保持此过程尽可能高效 - 实际上有 5 种不同的方式可以在 Java 中解析 XML,我在这里概述了它们以及优缺点。

任何将整个内容保存在 ram(DOM 或 XPath)中的东西都会占用大量内存。SAX 要好得多,但它仍然会在遇到元素时解析出元素并将它们交给您的处理程序实现,而 STAX 在您请求之前不会解析流中的任何内容;它只会向您发出事件,让您知道它在看什么。

话虽如此,我创建了基于 STAX 的SJXP 解析库,以提供具有 XPath 易用性的 STAX 性能。

您从字面上定义您感兴趣的文件中的路径,例如:

/message/data -- represents the <message><data>[STUFF HERE]</data></message> path

然后将所有路径(它们基本上是规则)提供给解析器,然后给它您要解析的文件,它会为您完成所有肮脏的工作,只有在找到您要求的内容时才调用您的代码。

该实现非常高效(我不是在开玩笑,我花了几天时间对其进行分析以获取低于基本 STAX 类的实现开销,因此它不会增加可测量的开销)并且超级易于使用。

注意您说每条消息附带的 byte[] 是“单独的文件”,我不确定您在 XML Parsing 上下文中的意思;我想我们中的一些人可能认为您的二进制数据是在您的 XML 消息中进行 base64 编码的,如果不是这种情况,并且您有辅助的数据有效负载,每条消息都通过网络传输,那么您将要做什么保持低内存使用率是将数据(一次一个块)从线路直接传输到数据库。

如果您的数据库不允许流式一次插入一个段的值并且需要整个 byte[] blob,那么只需将该 byte[] 从网络中取出并尽快放入 DB 以保持较低的内存使用率;如果这些确实是每个 1MB 的原始数据,那么这很可能是什么让你的堆爆炸,特别是如果有很多同时连接的情况。

如果您想分享有关您的 impl 的更多数据,我相信我们可以提供建议。

于 2012-03-01T15:35:02.087 回答
1

将您的数据从 XML 模型转换为 Java 模型,以便您可以将其转换为数据库模型,这对我来说是完全错误的。寻找支持 XML 到数据库而不通过 Java 对象的工具 - 如果您的数据库没有 XML 导入,请寻找第三方工具。Saxon 的 XSLT-SQL 模块可能无法处理二进制数据,但可能有一些工具可以。

于 2012-02-25T00:15:20.217 回答
1

您可以使用的最简单的方法是 DOM(Google 中有很多示例)。

它会预加载所有数据以构建内存中的树结构,因此速度会很快,而且由于 10 MB 不是那么大,您可以尝试一下(当然内存中的表示会更大)。

DOM 也是您可以使用的最简单/最简单的 API。

您可以尝试的另一个库是Simple XML。它非常轻巧,API 看起来很像JAXB,但更直观、更简单。

如果尝试这些,你仍然觉得你需要一些内存需求较少的东西,你可以使用一些基于流的解析器,例如 Stax,但 API 有很大不同,而且 IMO 有点“更难”使用

于 2012-02-25T10:10:15.710 回答
1

您可以使用 stax,它是快速摄取/生成 xml 的一个很好的答案。它现在是 jvm 的一部分,使用起来非常简单。你会喜欢它 :-)。

问题是您在阅读文件时清楚地管理每个元素和属性。您对元素(开始/结束)进行循环并轻松访问它们的属性。它可以让您精确地了解您想要做什么。此外,并非所有内容都像在 DOM 中那样加载到内存中。

网上有很多教程。这是我在 oracle 网站上找到的第一页。 http://docs.oracle.com/javaee/5/tutorial/doc/bnbem.html

于 2012-02-25T10:25:58.240 回答