2013-12-10 67 views
3

我需要處理具有以下結構的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.錯誤。我讀了它,我不認爲這是一個可調限制。

這裏有更多的事情,我想我應該嘗試:

  • 重新寫我的C#應用​​程序中使用非託管代碼
    • 我沒有與非託管代碼太多的經驗,所以我不確定它會如何工作,以及如何使它儘可能不受管理。
    • 我曾經寫過一個可以與我的攝像頭一起使用的小應用程序,接收圖像,反轉顏色並將其繪製到面板上。使用普通託管代碼無效 - 結果大約爲每秒2幀。重新寫入顏色反轉方法以使用非託管代碼解決了問題。這就是爲什麼我認爲非託管可能是解決方案。
  • 而是去C++中的C#
    • 不知道這是一個真正的解決方案代替。 C#會更好嗎?比非託管C#更好?
    • 這裏的問題是,我之前並沒有真正使用過C++,所以在開始使用C++之前,我需要了解一些關於C++的知識,然後可能不是很有效。

我認爲我會問一些建議之前,我去任何進一步的,可能是在浪費時間。

在此先感謝您的時間和協助。

編輯

所以我纔開始處理我通過它運行,並在嘗試提供反饋,以處理可能會花費多長時間用戶檢查大小的文件;我提出的計算的屏幕截圖:

18 minutes in; 1.67mil lines

這是每秒約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(); 
    } 

仍然運行過程中出現,在:(

+0

我認爲對XML的流處理的合理期望是大約1Gb /分鐘。當你說這是「很長時間」,你需要量化這個,所以我們可以看到你的期望是否合理。當然,你需要補充的是用數據做一些有用的事情的代價,比如將數據加載到數據庫中。 –

+0

感謝您的反饋邁克爾,請查看所需信息的更新後的帖子。這回答了你的問題了嗎? – that0th3rGuy

回答

2

27分鐘可以讀取XML作爲元素,而不是試圖讀取的邏輯流它行由行和一塊回來一起自己。看在end of this article

也代碼示例,你的問題已經被問here

+0

謝謝你的迴應。我正在實施並測試它。 – that0th3rGuy

+0

其他人的確曾問過這個問題,但據我所知,他們都沒有處理11GB的文件。將它加載到內存中並不真正起作用,逐行處理它實際上並不奏效。這是我的問題。 – that0th3rGuy

+0

我鏈接到的代碼應該逐個處理xml元素而不將其全部加載到RAM中 – radai