2012-02-18 47 views
2

我想創建一個XML文件,使用Java,這是GPS座標(GPX)的集合。每次我從我的android設備收到一個座標(大約每秒1次),我需要將結果追加到現有的XML文件中。我正在查找的輸出如下所示,trkpt元素作爲重複項目。問題是我不能只將新的trkpt添加到文件的末尾,因爲它需要位於trkseg父元素內。如何使用Java將子元素附加到大型XML文件?

到目前爲止,我已經嘗試了兩種不同的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> 
+0

你是否總是以同樣的方式追加數據?然後考慮只需逐行閱讀文件,並以'XML無關'的方式追加行;只要結果仍然是有效的XML。 – 2012-02-18 17:53:58

+1

您是否可以將數據追加到普通文件中,然後將整個文件轉換爲XML?或者可以批量轉換它?嘗試不斷更新XML看起來像使生活變得不必要的困難! ;-) – DNA 2012-02-18 17:55:06

+0

我想你的問題涉及到客戶端處理(android)而不是服務器端處理,對嗎? – home 2012-02-18 18:01:33

回答

0

總有一些瓶頸,當涉及到I/O,打開特別是當/關閉/重新打開的但卻難免重複方式的文件。

DOM處理程序將在每次打開文件時創建一個完整的樹結構,但在修改該樹時非常有效。

因此,首先,您是否真的需要打開,更改,保存每個滴答滴答的文件?如果沒有,請將文件的DOM保存在內存中,並通過對XML的引用進行更改。當用戶退出應用程序或離開視圖時保存。

如果您確實需要在每次打勾時保存該文件,您仍可以將DOM保存在內存中,並且只在每次打勾時將其保存到磁盤。

如果您需要在每個打勾上打開/保存/重新打開文件,請不要使用任何XML庫 - 只需使用標準FileWriter或類似內容,並手動更改內容 - 但它仍然會如果文件變得非常大,很難保持性能。

+0

我不一定需要在每次打勾時保存到文件。只要數據在等待寫入時沒有更大的可能性。我想我應該提到,數據量可能會進入GB範圍,因此在退出應用程序時可能會存在問題。 – Ferrari692 2012-02-18 18:44:12

+0

@ Ferrari692是的,你不應該在內存中保留這個大小的DOM對象。考慮使用其他方法,而不是分析整個文件的大小,無論是塊還是非XML。 – 2012-02-18 18:46:11

0

這聽起來像是SAX的完美應用(在包裝org.xml.sax中找到它);它是用於訪問和操作XML的流媒體API。 SAX爲其遇到的每個元素生成事件,允許您將文件複製到新文件中,而無需將其解析到大型內存樹中。當您到達輸入文件的末尾時,只需在處理結尾標記<trkseg>之前適當添加新元素即可。

當然你每秒重寫這個文件的方法本身聽起來有問題。你能把信息捆綁在更大的細分市場嗎?您可以將信息轉儲到單個文件並按特定時間間隔(每10/30/60秒)將其收集到一個文件中。

+0

我不會有捆綁信息和使用較大間隔的問題。我將研究使用SAX。 – Ferrari692 2012-02-18 18:49:39

0

如果它像這裏所述的那樣簡單,那麼您可以使用RandomAccessFile並尋找文件長度減去幾個字節(就在根結束標記之前),然後在那裏開始覆蓋。

+0

有趣。我將不得不嘗試一下。 – Ferrari692 2012-02-18 19:00:22

0

我建議將xml文件分成3部分。

head.xml

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

體。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));