C#處理XML大檔案遇到的多重宣告問題(這不是預期的 XML 宣告)_記憶體不足處理_未預期的結束標記

 
首先在一開始遇到的主要是有多個宣告出現在同一篇XML檔案中
由於遇到的需求是要我去解析匯入一個XML大檔案(平均超過700MB以上)
包含多份專利檔案

在一開始遇到的Exception 錯誤就是
這不是預期的 XML 宣告。XML 宣告必須在文件的第一個節點,且不允許在其前方出現空白字元。

通常一份XML只能有一個
<?xml version="1.0" encoding="UTF-8"?> 的宣告
有重複多個是不合法的XML格式

How to load XML File Source with multiple XML Declaration









因此一開始想到的策略就是一開始
不要直接先用XML API Load(string xml_path)進來(傳入的參數為一XML檔案路徑)

改先將重複宣告的這一句
<?xml version="1.0" encoding="UTF-8"?>
給取代掉
統一只在最一開始加上這一句宣告就好

結果



由於大檔案關係一次取代會導致記憶體不足
遇到的第二個例外錯誤
System.OutOfMemoryException

這裡已經測試過直接一口氣Load到記憶體存的
例如MemoryStream
XML API Load 跟 LoadXml都是不可行的
只能改成一行一行讀取的方式(不要一次讀進內存)
因此未來必須捨棄掉對XmlDocument 仰賴XPATH 相關API (SelectNodes,SelectSingleNode)作法

.NET XML API 中 XmlTextReader 、 XmlReader (XmlTextReader 的抽象Base Class)雖能夠一行一行讀取
使記憶體不足問題得以克服但又會遭遇到
這不是預期的 XML 宣告。XML 宣告必須在文件的第一個節點,且不允許在其前方出現空白字元。

當讀取到重複宣告的該行就又會報此錯

我希望當滾while一行一行讀取時候當出現此例外就continue來忽略
直接做下一行處理



不過XMLTextReader 的Read 只要讀取一有問題就會中斷
且也無法指定換下一行讀取



因此後來改為先用一般讀文字檔方式StreamReader的 ReadLine()
來獲取XML大檔的每一行

只不過
緊接著又遇到第三個例外錯誤
未預期的結束標記。


看來XmlReader(XmlTextReader)不接受一行一行讀XML文字檔情況(不能夠將成對的XML Tag方開讀取)

這個需求可真是三個BUG一次滿足啊= =|||


最後再次統整一次解問題思路

由於目前面對的是一個XML檔案包含多個單篇的XML文件(算合集)
會有重複的開頭宣告不合法問題此外大檔案關係若一次讀入記憶體會有memory爆掉問題
因此
Step1.只要先透過一般StringReader一行行讀進
Step2.一個一個用StringBuilder組成單篇XML的內文
Step3.透過LoadXml(string content) 將內文字串讀進變成XmlDocument由於單篇的部分XML內文
不會太多因此不會造成記憶體不足,更可以再次重拾XPATH相關API













Ref:
XML宣告(declaration)必須在第一行的第一個字元

請問XmlTextReader 讀到首行是空白行該如何處理

OutOfMemoryException while using string.replace()

Reading large text files with streams in C#

Reading a specific line with StreamReader

.NET XML Best Practices: Reading XML Documents

Out of Memory Exception while reading large XML file

How to overcome OutOfMemoryException pulling large xml documents from an API?









留言

這個網誌中的熱門文章

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header

經得起原始碼資安弱點掃描的程式設計習慣培養(三)_7.Cross Site Scripting(XSS)_Stored XSS_Reflected XSS All Clients

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題