2014-03-07 67 views
9

我有一個巨大的XML文件(15 GB)。我想將XML文件中的「文本」標籤轉換爲單個頁面。巨大的XML文件到文本文件

示例XML文件:

<root> 
    <page> 
     <id> 1 </id> 
     <text> 
     .... 1000 to 50000 lines of text 
     </text> 
    </page> 
    ... Like wise 2 Million `page` tags 
</root> 

我最初使用DOM解析器,但它MEMORY(有效),將引發JAVA OUT。現在,我已經使用STAX編寫了JAVA代碼。它運作良好,但表現非常慢。

這是我寫的代碼:

XMLEventReader xMLEventReader = XMLInputFactory.newInstance().createXMLEventReader(new FileInputStream(filePath)); 
    while(xMLEventReader.hasNext()){ 
     xmlEvent = xMLEventReader.nextEvent(); 

    switch(xmlEvent.getEventType()){ 
    case XMLStreamConstants.START_ELEMENT: 
    if(element == "text") 
     isText = true; 
    break; 
    case XMLStreamConstants.CHARACTERS: 
     chars = (Characters) xmlEvent; 
     if(! (chars.isWhiteSpace() || chars.isIgnorableWhiteSpace())) 
       if(isText) 
       pageContent += chars.getData() + '\n'; 
     break; 
    case XMLStreamConstants.END_ELEMENT: 
     String elementEnd = (((EndElement) xmlEvent).getName()).getLocalPart(); 
     if(elementEnd == "text") 
     { 
      createFile(id, pageContent); 
      pageContent = ""; 
      isText = false; 
     } 
     break; 
    } 
} 

此代碼工作良好(忽略任何小錯誤)。根據我的理解,XMLStreamConstants.CHARACTERS迭代每個文本標籤的行。如果TEXT標籤中有10000行,則XMLStreamConstants.CHARACTERS會迭代接下來的10000行。有沒有更好的方法來提高性能..?

+0

出於好奇,目前需要多長時間才能加載和解析該文件? –

+0

我已解析2GB文件。花了35分鐘.. – user1919035

+4

什麼是'pageContent'?它是一個「字符串」嗎?如果是這樣,一個簡單的優化就可以使用'StringBuilder'來代替;它可以追加字符串,而不必像字符串''''='那樣創建全新的字符串副本(如果你有一個長度的概念,你也可以用一個初始的保留容量來構造它來減少內存重新分配和副本首先)。 –

回答

1

什麼是pageContent?它似乎是一個String。一個簡單的優化就可以立即使用StringBuilder代替;它可以附加字符串,而不必像字符串String s +=那樣創建全新的字符串副本(如果您對長度有所瞭解,也可以使用初始保留容量來減少內存重新分配和副本)。

連接String s是一個緩慢的操作,因爲字符串在Java中是不可變的;每次你撥打a += b它必須分配一個新的字符串,複製a,然後複製b到它的結尾;使每個串聯O(n)wrt。兩個琴絃的總長度。追加單個字符也一樣。另一方面,StringBuilder與追加時的ArrayList具有相同的性能特徵。所以,你必須:

pageContent += chars.getData() + '\n'; 

而是改變pageContentStringBuilder,做:

pageContent.append(chars.getData()).append('\n'); 

此外,如果您有上限,這些字符串之一的長度的猜測,你可以通過它給StringBuilder構造函數分配初始容量並減少內存重新分配和完全複製的機會。

順便說一下,另一個選項是完全跳過StringBuilder並將數據直接寫入輸出文件(假設您不是先處理數據)。如果您這樣做,並且性能受到I/O限制,則在另一個物理磁盤上選擇輸出文件可能會有所幫助。

0

您的代碼看起來很標準。 但是,您可以嘗試將FileInputStream包裝到BufferedInputStream中,並讓我們知道這是否有幫助? BufferedInputstream可以節省很少的OS本地調用,所以有更好的性能。 你必須利用緩衝區大小來獲得最佳性能。根據您的JVM內存分配設置一些大小。

+0

實際上,它爲您節省了很多系統調用,而實際上8192的默認緩衝區大小几乎適用於所有場合。 – EJP

+0

謝謝..我已經實現了這個..我正在尋找任何其他過程遵循.. – user1919035

1

嘗試使用SAX解析器進行解析,因爲DOM會嘗試解析整個內容並將其放在內存中。正因爲如此,你得到了內存異常。 SAX解析器不會一次解析整個內容。

+2

他交換到STAX解析器,它將執行以及SAX解析器 –

+0

我已經使用STAX .. – user1919035

4

我可以看到一些可能的解決辦法的事情,可能會幫助你:

  1. 使用BufferedInputStream,而不是一個簡單的FileInputStream以減少磁盤操作的數量
  2. 考慮使用StringBuilder創建您pageContent而不是String連接。
  3. 如果你使用2GB示例進行內存綁定,請增加Java堆(-Xmx選項)。

它可以在這樣的情況下,掛鉤代碼分析器(例如Java VisualVM)挺有意思的,你就能夠看到什麼方法調用中正在代碼內緩慢。然後,您可以適當地重點優化。

0
  1. 使用BufferedInputStream圍繞FileInputStream.
  2. 不連接的數據。這是對時間和空間的完全浪費,可能有很多空間。寫出來,立即得到它。爲此,圍繞FileWriter使用BufferedWriter
+0

我' m使用FileWriter周圍的BufferedWriter .. – user1919035

2

如果解析XML文件是主要問題,請考慮使用VTD-XML,即擴展版本,因爲它支持的文件最大爲256GB。

由於它基於非抽取式文檔解析,因此具有很高的內存效率,並且使用它來使用XPath查詢/提取文本的速度也非常快。您可以從here閱讀關於此方法和VTD-XML的更多詳細信息。