2013-10-18 42 views
4

我喜歡Linq to Xml API。我曾經使用過的最簡單的一個。Linq to Xml:XDocument是緩存閱讀器嗎?

我還記得它的實施上面XmlReader,這是一種非緩存讀取,這意味着:

var rdr = XmlReader.Create("path/to/huge_3Gb.xml"); 

...會立即返回(有可能讀,頂多XML頭)。

documentation對於XDocument.Load()表明確實使用XmlReader.Create()

我預料,像所有的東西Linq,我會得到與Linq2Xml的延期執行行爲。
但後來我想這一點,像我通常做什麼觸動文件:

using(var xdoc = XDocument.Load("file")){ ... } 

和驚喜!它不會編譯,因爲XDocument不會執行IDisposable

嗯,這是奇特的! 有沒有當我完成使用XDocument時釋放文件句柄?

然後它對我恍然大悟:也許XDocument.Load()立即吃掉了整個Xml(並立即關閉文件句柄)?

所以,我想:

var xdoc = XDocument.Load("path/to/huge_3Gb.xml"); 

,等待着,等待着,然後該過程說:

Unhandled Exception: OutOfMemoryException. 

因此LINQ到XML是接近完美(真棒API),但沒有雪茄(當在大型Xmls上使用時)。

</rant>

我的問題是:

  1. 我缺少的東西並沒有使用LINQ到XML懶洋洋的方式?

  2. 如果回答前一個問題是 '否':

是否有客觀原因的LINQ to XML API已經不能推遲類似的,比方說,LINQ到對象的行爲呢?在我看來,至少有一些操作(例如,只有前向XmlReader纔有可能)可以延遲執行。

...或者是它沒有這樣實現的,引用Eric Lippert

「因爲從來沒有人設計,指定,實現,測試,記錄 和運輸該功能」?

回答

6

其實Linq to Xml使用延遲執行。但它查詢內存數據,而不是來自文件的數據。您可以從文件,數據流,字符串或手動生成文檔加載數據 - 無論內存節點圖如何構建都無關緊要。 Linq to xml用於查詢xml樹的內存表示(即對象圖)。

這是一個示例,顯示延遲執行與Linq到Xml的工作方式。考慮你的XDocument它包含下列數據對象圖:

<movies> 
    <movie id="1" name="Avatar"/> 
    <movie id="2" name="Doctor Who"/> 
</movies> 

不要緊,你將如何創建內存XML數據的代表性。例如。

var xdoc = XDocument.Parse(xml_string); 
// or XDocument.Load(file_name); 
// or new XDocument(new XElement("movies"), ...) 

現在定義查詢:

var query = xdoc.Descendants("movie"); 

您可以修改內存中的XML表示,該文件包含:

xdoc.Root.Add(new XElement("movie"), new XAttribute("id", 3)); 

現在執行查詢:

int moviesCount = query.Count(); // returns 3 

正如你所看到的,Linq到Xm l使用延遲執行,但它與Linq到Objects類似 - 在此查詢內存中的數據。

注意:XDocument沒有實現IDisposable,因爲在構造節點圖之後它不包含任何非託管資源。

+0

很好的解釋。我只是希望懶惰的行爲會滲透到提供者。這是「淺」延期執行,對大文件沒有太大幫助。 –

+1

@CristiDiaconescu這就是Linq到Xml的工作方式 - 您首先需要創建文檔(即讀取文件),然後才能查詢它。 Linq to Xml需要內存中的所有數據,與舊的XmlDocument完全一樣。所以,對於龐大的數據並不好。其實我不認爲Xml文件是適用於龐大數據的合適數據存儲。通常在這種情況下使用數據庫。 –