注册表访问非常复杂。你基本上是在阅读一个大的二叉树。类设计应该在很大程度上依赖于存储的数据结构。只有这样,您才能选择合适的班级设计。为了保持灵活性,您应该对诸如 REG_SZ、REG_EXPAND_SZ、DWORD、SubKey 等原语进行建模。Don Syme 在他的专家 F# 一书中有一个关于使用二进制组合器进行二进制解析的精彩部分。基本思想是您的对象自己知道如何从二进制表示中反序列化。当您有一个结构如下的字节流时
<Header> <Node1/>
<Node2> <Directory1>
</Node2> </Header>
您从 BinaryReader 开始逐字节读取二进制对象。既然你知道第一件事必须是标题,你可以将它传递给 Header 对象
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 应用的一种解决方案是将整个文件分配在分页池内存中,该内存可以跨越数 GB,但只有实际访问的部分从磁盘换出到内存中。这允许 Windows 以有效的方式处理非常大的注册表文件。您的读者也需要类似的东西。延迟解析是一方面,在文件中跳转而不需要读取中间数据的能力对于保持性能至关重要。
有关分页池和注册表的更多信息可以在此处找到:http:
//blogs.technet.com/b/markrussinovich/archive/2009/03/26/3211216.aspx
您的 Api 设计将取决于您如何读取数据以保持效率(例如,使用内存映射文件并从不同的映射区域读取)。使用 .NET 4,内存映射文件实现已经到来,现在非常好,但围绕 OS API 的包装器也存在。
你的,阿洛伊斯克劳斯
为了支持从内存映射文件延迟加载,不将字节数组读入对象并稍后解析它是有意义的,而是更进一步并仅存储内存映射文件中内存块的偏移量和长度。稍后当实际访问对象时,您可以读取和反序列化数据。这样,您可以遍历整个文件并构建一个对象树,其中仅包含偏移量和对内存映射文件的引用。这应该可以节省大量内存。