1

MyClass就是提供对单个文件的访问。它必须CheckHeader(), ReadSomeData(), UpdateHeader(WithInfo), 等等

但是由于这个类所代表的文件非常复杂,所以需要特殊的设计考虑。

该文件包含具有各种节点类型的潜在巨大的类似文件夹的树结构,并且基于块/单元以更好地处理碎片。大小通常小于 20 MB。这不是我的设计。

你会如何设计这样一个类?

  • 将约 20MB 的流读入内存?
  • 将副本放在临时目录并将其路径保留为属性?

  • 在内存中保留一份重要内容并将它们公开为只读属性?
  • GetThings()从带有异常抛出代码的文件中?

这个类一开始只会由我使用,但如果它结束得足够好,我可能会开源它。

(这是一个关于设计的问题,但平台是 .NET,课程是关于 XP 的离线注册表访问)

4

2 回答 2

3

这取决于您需要如何处理这些数据。如果您只需要线性处理一次,那么只对内存中的大文件进行性能打击可能会更快。

但是,如果您需要对文件执行各种操作,而不是单一的线性解析,我会将数据解析到轻量级数据库(如 SQLite)中,然后对其进行操作。这样,您的所有文件结构都将被保留,并且对文件的所有后续操作都会更快。

于 2010-09-05T01:18:30.100 回答
1

注册表访问非常复杂。你基本上是在阅读一个大的二叉树。类设计应该在很大程度上依赖于存储的数据结构。只有这样,您才能选择合适的班级设计。为了保持灵活性,您应该对诸如 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 的包装器也存在。

你的,阿洛伊斯克劳斯

为了支持从内存映射文件延迟加载,不将字节数组读入对象并稍后解析它是有意义的,而是更进一步并仅存储内存映射文件中内存块的偏移量和长度。稍后当实际访问对象时,您可以读取和反序列化数据。这样,您可以遍历整个文件并构建一个对象树,其中仅包含偏移量和对内存映射文件的引用。这应该可以节省大量内存。

于 2010-09-08T22:21:50.210 回答