Доступ к реестру довольно сложный. Вы в основном читаете большое двоичное дерево. Дизайн класса должен сильно зависеть от хранимых структур данных. Только тогда вы сможете выбрать подходящий дизайн класса. Чтобы оставаться гибким, вы должны смоделировать примитивы, такие как REG_SZ, REG_EXPAND_SZ, DWORD, SubKey, .... Дон Сайм имеет в своей книге Expert F # хороший раздел о двоичном разборе с помощью двоичных комбинаторов. Основная идея заключается в том, что ваши объекты сами знают, как десериализовать из двоичного представления. Когда у вас есть поток байтов, который имеет такую структуру
вы начинаете с 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-дизайн будет зависеть от того, как вы считываете данные, чтобы оставаться эффективными (например, используйте отображенный в память файл и считываете из разных отображаемых областей). В .NET 4 появилась реализация файла Memory Mapped, которая в настоящее время неплоха, но существуют также обертки вокруг API-интерфейсов ОС.
С уважением,
Алоис Краус
Для поддержки отложенной загрузки из файла с отображением в память имеет смысл не считывать байтовый массив в объект и анализировать его позже, а делать один шаг вперед и сохранять только смещение и длину фрагмента памяти из файла, отображаемого в память , Позже, когда объект действительно доступен, вы можете прочитать и десериализовать данные. Таким образом, вы можете пройти весь файл и построить дерево объектов, которое содержит только смещения и ссылку на файл, отображенный в памяти. Это должно сэкономить огромное количество памяти.