我需要處理具有以下結構的XML文件:過程非常大的XML文件
<FolderSizes>
<Version></Version>
<DateTime Un=""></DateTime>
<Summary>
<TotalSize Bytes=""></TotalSize>
<TotalAllocated Bytes=""></TotalAllocated>
<TotalAvgFileSize Bytes=""></TotalAvgFileSize>
<TotalFolders Un=""></TotalFolders>
<TotalFiles Un=""></TotalFiles>
</Summary>
<DiskSpaceInfo>
<Drive Type="" Total="" TotalBytes="" Free="" FreeBytes="" Used=""
UsedBytes=""><![CDATA[ ]]></Drive>
</DiskSpaceInfo>
<Folder ScanState="">
<FullPath Name=""><![CDATA[ ]]></FullPath>
<Attribs Int=""></Attribs>
<Size Bytes=""></Size>
<Allocated Bytes=""></Allocated>
<AvgFileSz Bytes=""></AvgFileSz>
<Folders Un=""></Folders>
<Files Un=""></Files>
<Depth Un=""></Depth>
<Created Un=""></Created>
<Accessed Un=""></Accessed>
<LastMod Un=""></LastMod>
<CreatedCalc Un=""></CreatedCalc>
<AccessedCalc Un=""></AccessedCalc>
<LastModCalc Un=""></LastModCalc>
<Perc><![CDATA[ ]]></Perc>
<Owner><![CDATA[ ]]></Owner>
<!-- Special element; see paragraph below -->
<Folder></Folder>
</Folder>
</FolderSizes>
的<Folder>
元件是特殊的,因爲它重複<FolderSizes>
元件內,但也可出現在其自身內;我估計大概有5個關卡。
問題是該文件真的很大,高達11GB,所以我處理它有困難 - 我有XML文檔的經驗,但沒有這個規模。
我想要做的是將信息導入到SQL數據庫中,因爲那樣我就能夠以任何必要的方式處理信息,而不必關心這個龐大而不切實際的文件。
以下是我已經試過的東西:
- ,只需加載該文件,並嘗試使用一個XmlDocument或XDocument對象有一個簡單的C#程序來處理它
- 之前,我甚至開始我就知道這因爲我敢肯定每個人都會同意,但我仍然嘗試過,並且在VM上運行應用程序(因爲我的筆記本電腦只有4GB內存),並具有30GB內存。該應用程序結束了使用24GB的內存,並採取非常非常長,所以我剛剛取消它。
- 嘗試使用XmlReader對象
- 這種方法來處理文件工作,因爲它沒有使用盡可能多的內存更好,但我仍然有一些問題:
- 這是花了很長時間,因爲我一次只讀一行文件。
- 一次處理一行文件使得真正處理XML中包含的數據非常困難,因爲現在您必須檢測標記的開始,然後檢測該標記的結尾(希望),然後創建來自該信息的文檔,閱讀信息,嘗試確定它屬於哪個父標籤,因爲我們有多個級別...聲音容易出現問題和錯誤
- 我提到它需要很長的時間閱讀文件一行時間;而且還沒有真正處理這條線 - 從字面上看它只是閱讀它。
- 這種方法來處理文件工作,因爲它沒有使用盡可能多的內存更好,但我仍然有一些問題:
- 導入使用SQL Server
- 的信息,我創建使用XQuery和自身內部遞歸運行它處理
<Folder>
元素的存儲過程。這很順利 - 我認爲比其他兩種方法更好 - 直到<Folder>
元素中的一個最終變得相當大,產生了An XML operation resulted an XML data type exceeding 2GB in size. Operation aborted.
錯誤。我讀了它,我不認爲這是一個可調限制。
- 的信息,我創建使用XQuery和自身內部遞歸運行它處理
這裏有更多的事情,我想我應該嘗試:
- 重新寫我的C#應用程序中使用非託管代碼
- 我沒有與非託管代碼太多的經驗,所以我不確定它會如何工作,以及如何使它儘可能不受管理。
- 我曾經寫過一個可以與我的攝像頭一起使用的小應用程序,接收圖像,反轉顏色並將其繪製到面板上。使用普通託管代碼無效 - 結果大約爲每秒2幀。重新寫入顏色反轉方法以使用非託管代碼解決了問題。這就是爲什麼我認爲非託管可能是解決方案。
- 而是去C++中的C#
- 不知道這是一個真正的解決方案代替。 C#會更好嗎?比非託管C#更好?
- 這裏的問題是,我之前並沒有真正使用過C++,所以在開始使用C++之前,我需要了解一些關於C++的知識,然後可能不是很有效。
我認爲我會問一些建議之前,我去任何進一步的,可能是在浪費時間。
在此先感謝您的時間和協助。
編輯
所以我纔開始處理我通過它運行,並在嘗試提供反饋,以處理可能會花費多長時間用戶檢查大小的文件;我提出的計算的屏幕截圖:
這是每秒約1500線;如果平均行長度大約爲50個字符,即每行50個字節,即每秒75千字節,如果我的數學正確,那麼對於11GB文件應該需要大約40個小時。但是這只是逐步走上每條線。它並不實際處理線路或對其做任何事情,所以當它開始時,處理速率顯着下降。
這是尺寸計算過程中運行的方法,包括:
private int _totalLines = 0;
private bool _cancel = false; // set to true when the cancel button is clicked
private void CalculateFileSize()
{
xmlStream = new StreamReader(_filePath);
xmlReader = new XmlTextReader(xmlStream);
while (xmlReader.Read())
{
if (_cancel)
return;
if (xmlReader.LineNumber > _totalLines)
_totalLines = xmlReader.LineNumber;
InterThreadHelper.ChangeText(
lblLinesRemaining,
string.Format("{0} lines", _totalLines));
string elapsed = string.Format(
"{0}:{1}:{2}:{3}",
timer.Elapsed.Days.ToString().PadLeft(2, '0'),
timer.Elapsed.Hours.ToString().PadLeft(2, '0'),
timer.Elapsed.Minutes.ToString().PadLeft(2, '0'),
timer.Elapsed.Seconds.ToString().PadLeft(2, '0'));
InterThreadHelper.ChangeText(lblElapsed, elapsed);
if (_cancel)
return;
}
xmlStream.Dispose();
}
仍然運行過程中出現,在:(
我認爲對XML的流處理的合理期望是大約1Gb /分鐘。當你說這是「很長時間」,你需要量化這個,所以我們可以看到你的期望是否合理。當然,你需要補充的是用數據做一些有用的事情的代價,比如將數據加載到數據庫中。 –
感謝您的反饋邁克爾,請查看所需信息的更新後的帖子。這回答了你的問題了嗎? – that0th3rGuy