註冊表的訪問是相當複雜的。你基本上正在閱讀一個大的二叉樹。類設計應該非常依賴存儲的數據結構。只有這樣你才能選擇合適的班級設計。爲了保持靈活性,您應該爲諸如REG_SZ,REG_EXPAND_SZ,DWORD,SubKey等基元建模。Don Syme在他的書Expert F#中介紹了一個關於使用二元組合器進行二進制解析的很好的部分。基本思想是你的對象通過自己知道如何從二進制表示反序列化。當你有其被構造這樣
<部首> <節點1/>
<節點2 > < directory1中>
< /節點2 > < /部首>
字節流
從BinaryReader開始逐字節讀取二進制對象。既然你知道的第一件事一定是頭,你可以將它傳遞給頭對象
public class Header
{
static Header Deserialize(BinaryReader reader)
{
Header header = new Header();
int magic = reader.ReadByte();
if(magic == 0xf4) // we have a node entry
header.Insert(Node.Read(reader);
else if(magic == 0xf3) // directory entry
header.Insert(DirectoryEntry.Read(reader))
else
throw NotSupportedException("Invalid data");
return header;
}
}
要保持高性能,你可以如延遲解析數據直到稍後訪問該實例或該實例的特定屬性。
由於Windows中的註冊表可能會變得很大,因此無法一次將其完全讀入內存。你需要將它組裝起來。 Windows應用的一個解決方案是將整個文件分配到頁面緩衝池內存中,該內存可以跨越幾千兆字節,但只有實際訪問的部分從磁盤換出到內存中。這允許Windows以有效的方式處理非常大的註冊表文件。您的閱讀器也需要類似的東西。延遲解析是一個方面,無需讀取數據就可以在文件中跳轉,這對於保持高性能是非常有用的。
更多關於分頁池和註冊表中的相關信息可以在那裏找到: http://blogs.technet.com/b/markrussinovich/archive/2009/03/26/3211216.aspx
你的API的設計將取決於你如何讀取數據保持有效(例如使用memory mapped file並從不同的映射區域讀取)。在.NET 4中,內存映射文件實現已經到來,現在已經相當不錯了,但是OS API的封裝也存在。
你的, 阿洛伊斯·克勞斯
以支持從內存映射文件延遲加載它將使意義不讀字節數組對象,後來分析,但走一步furhter和存儲僅偏移和來自內存映射文件的內存塊的長度。稍後當實際訪問對象時,您可以讀取和反序列化數據。這樣你可以遍歷整個文件並構建一個只包含偏移量和對內存映射文件的引用的對象樹。這應該可以節省大量的內存。
找到像你這樣有用的答案是非常棒的,感謝支持! :)我的第一份草案是一個有getter的getter類,頭部有GetHash等的類,它們不會被緩存,所以類的用戶可以選擇緩存 - 你認爲這有意義嗎?我想稍後很容易維護/重構,因爲我害怕我必須在某個時刻。 – 2010-09-09 04:40:55
其實我認爲這就是你的意思,但只是爲了確保,我目前的想法是,除了它們的序列化二進制表示和從錯誤拋出獲取器返回組件對象外,對象不會保留任何緩存。因此,這意味着將1-50 MB的字節數組保存爲只讀屬性(這樣的大小受益於內存映射文件?)並從中創建對象。 – 2010-09-09 04:46:26
要將字節數組讀入對象是有問題的,因爲您已經使用了相當多的內存。最好只獲取相對於內存映射文件起點的偏移量,並僅在實際訪問對象時讀取數據。 – 2010-09-09 16:13:36