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

时间:2012-02-18 17:49:49

标签: java android xml api gpx

我正在尝试使用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>

4 个答案:

答案 0 :(得分:0)

在I / O方面总是存在瓶颈,特别是在以反复方式打开/关闭/重新打开文件时。

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

首先,你真的需要打开,更改,保存每个滴答的文件吗?如果没有,请将文件的DOM保留在内存中,并通过对XML的引用进行更改。用户退出应用程序或离开视图时保存。

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

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

答案 1 :(得分:0)

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

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

答案 2 :(得分:0)

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

答案 3 :(得分: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));