如何使用 Java 将子元素附加到大型 XML 文件?

问题描述 投票:0回答:4

我正在尝试使用 Java 创建一个 XML 文件,它是 GPS 坐标 (GPX) 的集合。每次我从 Android 设备收到坐标(大约每秒 1 个)时,我都需要将结果附加到现有的 XML 文件中。我正在寻找的输出如下所示,其中 trkpt 元素作为重复项。问题是我不能只将新的 trkpt 添加到文件末尾,因为它需要位于 trkseg 父元素内。

到目前为止,我已经尝试了两种不同的 API:SIMPLEXML 和 JDOM。使用 SIMPLEXML,我无法弄清楚如何将子元素附加到现有文件,因此我切换到 JDOM。 JDOM 允许我附加 trkpt 元素,如下所示,但随着文件开始增长,它很快减慢了程序的用户界面。对于 JDOM,我使用 SAXBuilder 重新打开文件并追加。我认为这个问题是它必须在添加新元素并重写文件之前在内存中重现整个文件。因此文件越大,对设备的操作要求就越高。我需要一个在写入新数据之前不检查/复制整个文件的解决方案。有没有更有效的方法可以使用 Java 或 Java API 来完成此任务?感谢您的帮助!

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1">
        <trk>
            <trkseg>
                <trkpt lon="9.860624216140083" lat="54.9328621088893">
                    <ele>228.0</ele>
                </trkpt>
                <trkpt lon="9.860624216140100" lat="54.9328621088754">
                    <ele>234.0</ele>
                </trkpt>
                <trkpt lon="9.860624216140343" lat="54.9328621088678">
                    <ele>227.0</ele>
                </trkpt>
            </trkseg>
        </trk>
</gpx>
java android xml api gpx
4个回答
0
投票

I/O 总是存在瓶颈,尤其是在重复打开/关闭/重新打开文件时。

DOM 处理程序每次打开文件时都会创建一个完整的树结构,但在更改该树时非常有效。

首先,您真的需要在每次更新时打开、更改、保存文件吗?如果不是,请将文件的 DOM 保留在内存中,并通过对 XML 的引用进行更改。当用户退出应用程序或离开视图时保存。

如果您确实需要在每个刻度时保存文件,您仍然可以将 DOM 保留在内存中,并且仅在每个刻度时将其保存到磁盘。

如果您需要在每个刻度上打开/保存/重新打开文件,请不要使用任何 XML 库 - 只需使用标准 FileWriter 或类似的文件,手动更改内容 - 但仍然很难如果文件变得非常大,保持性能。


0
投票

这听起来像是 SAX 的完美应用程序(在包中找到它

org.xml.sax
);它是一个用于 XML 访问和操作的流式 API。 SAX 为其遇到的每个元素生成事件,允许您将文件复制到新文件,而无需将其解析为大型内存树。当您到达输入文件的末尾时,只需在处理
<trkseg>
的结束标记之前根据需要附加新元素。

当然,您每秒重写此文件的方法本身听起来就有问题。您能否将信息捆绑到更大的部分中?您可以将信息转储到单个文件中,并以一定的时间间隔(每 10/30/60 秒)将它们收集到单个文件中。


0
投票

如果像这里所说的那么简单,您可以只使用 RandomAccessFile 并查找文件长度减去几个字节(就在根结束标记之前),然后开始覆盖那里。


0
投票

我建议将 xml 文件分成 3 部分。

head.xml

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns="http://www.topografix.com/GPX/1/1">
    <trk>
        <trkseg>

body.xml

<trkpt lon="9.860624216140083" lat="54.9328621088893">
    <ele>228.0</ele>
</trkpt>
<trkpt lon="9.860624216140100" lat="54.9328621088754">
    <ele>234.0</ele>
</trkpt>
<trkpt lon="9.860624216140343" lat="54.9328621088678">
    <ele>227.0</ele>
</trkpt>

tail.xml

        </trkseg>
    </trk>
</gpx>

现在,每当您获得新数据时,只需将其附加到 body.xml

要读取 xml 文件,请使用 SequenceInputStream,如下所示:

List<InputStream> list = new ArrayList<InputStream>(3);
list.add(new FileInputStream("head.xml"));
list.add(new FileInputStream("body.xml"));
list.add(new FileInputStream("tail.xml"));
InputStream xmlStream = new SequentialInputStream(Collections.enumeration(list));
© www.soinside.com 2019 - 2024. All rights reserved.