2010-10-19 123 views
14

我需要一個xml解析器來解析大約1.8 GB的文件。
所以分析器不應該加載所有的文件到內存。大型文件的Java XML解析器

有什麼建議嗎?

+0

1.8 gb是一個巨大的文本文件。在文件級不可能把它分成幾塊? – Owen 2010-10-19 15:01:24

+1

@Owen - 這取決於你的域名。當與來自其他人的系統的數據轉儲進行交互時,這種情況可能非常容易發生。 – 2010-10-19 15:03:34

+0

我沒有想到,但我想我們再次需要這樣一個解析器,以避免損壞的XML文件?做這種手動或任何建議怎麼做都不實際? – mehmet6parmak 2010-10-19 15:05:06

回答

19

除了推薦的SAX解析,您可以使用包含在JDK(包javax.xml.stream)中的StAX API(一種SAX演變)。

+1

雖然我同意StAX通常是最好的解決方案,但在某些情況下SAX更好。如果您的文檔包含大量文本內容,則AFAIR StAX API將完全讀取內存中的這些文本塊,並將其作爲單個事件處理。 SAX解析器通常會將它分成更小的塊,並將其分段供給處理程序。不保證能夠利用這個機會,但是在StAX中,這個機會甚至不存在。 (我個人覺得對於流媒體API有點尷尬。) – 2010-12-15 13:15:42

+0

問候可以有人請在這裏提高我的理解。因爲我有關於這個問題的面試問題,我回答的關鍵詞是'sax'和'thread',但他仍然需要第三個關鍵詞我回答執行者線程池...他說是和?!〜答案是優先級隊列can some一個解釋如何 – shareef 2015-01-13 17:06:00

+0

@ wilfred-springer Coalesce是一個可以在XMLInputFactory上設置的功能 - StAX API通常以與SAX相同的方式支持此功能。例如參見FasterXML inputfactory。 – ThomasRS 2015-03-05 09:59:50

1

幾乎可以使用任何SAXParser來一次傳輸文件。

3

將文件流式傳輸到SAX解析器中,並以塊爲單位將其讀入內存中。

SAX爲您提供了很多控制,並且事件驅動很有意義。 api有點難以掌握,你必須注意一些事情,比如何時調用了characters()方法,但基本思想是你編寫了一個內容處理程序,當每個程序的開始和結束被調用時讀取xml元素。因此,您可以跟蹤文檔中當前的xpath,確定哪些路徑具有您感興趣的數據,並確定哪條路徑標記了要保存或切換或以其他方式處理的塊的末尾。

10

使用基於SAX的解析器,它向您顯示事件流中文檔的內容。

3

嘗試VTD-XML。我發現它比SAX更高效,更重要的是,它更易於使用。

+0

GPL的授權如何? – 2017-11-28 11:35:58

3

正如其他人所說,使用SAX解析器,因爲它是一個流解析器。使用各種事件,您可以根據需要提取信息,然後在其他位置(數據庫,另一個文件,您有什麼)進行存儲。

如果您真的只需要一小部分子集,或者只是簡單歸納文件,您甚至可以將它存儲在內存中。當然取決於用例。

如果您正在假脫機數據庫,確保您採取一些謹慎措施,使您的過程可重新啓動或任何。在1.8GB中可能發生很多可能會在中間失敗的情況。

4

StAX的API是比較容易處理相比,SAX與。這裏是一個用於StaX的short tutorial

+0

+10爲有用的教程 – 2010-10-19 15:33:30

0

+1。它比SaX更易於使用,因爲您不需要編寫回調(您基本上只是循環遍歷所有元素,直到完成),並且對於它可以處理的文件的大小(AFAIK)沒有限制。

1

我有一個類似的問題 - 我不得不讀一個完整的XML文件並在內存中創建一個數據結構。在這個數據結構上(整個事情都必須加載),我不得不做各種操作。很多XML元素包含文本(我必須在輸出文件中輸出這些文本,但對算法來說不重要)。首先,如這裏所建議的,我使用SAX來解析文件並構建我的數據結構。我的文件是4GB,我有一個8GB的機器,所以我認爲可能3GB的文件只是文本和java.lang。對於使用UTF-16的文本,字符串可能需要6GB。

如果JVM佔用比計算機有物理RAM更多的空間,那麼機器將交換。做一個標記+清理垃圾回收會導致頁面以隨機順序訪問,而且對象也會從一個對象池移動到另一個對象池,這基本上會導致機器死機。

因此,我決定把所有的字符串寫入磁盤中的一個文件中(FS顯然可以處理3GB的順序寫入就好了,並且在操作系統中讀取它時將使用可用內存作爲文件系統緩存;可能仍然有隨機訪問讀取,但比java中的GC少)。我創建了一個小幫手類,如果它可以幫助你,歡迎下載:StringsFile javadoc | Download ZIP

StringsFile file = new StringsFile(); 
StringInFile str = file.newString("abc");  // writes string to file 
System.out.println("str is: " + str.toString()); // fetches string from file