MyClass
就是提供对单个文件的访问权限。它必须CheckHeader()
,ReadSomeData()
,UpdateHeader(WithInfo)
等
但由于此类表示的文件非常复杂,因此需要特殊的设计考虑因素。
该文件包含具有各种节点类型的潜在巨大的类文件夹树结构,并且基于块/单元以更好地处理碎片。大小通常小于20 MB。 这不是我的设计。
你会如何设计这样的课程?
GetThings()
来自带有异常抛出代码的文件?这个类一开始只供我使用,但如果它结束得好,我可以开源。
(这是关于设计的问题,但平台是.NET,类是关于XP的离线注册表访问)
答案 0 :(得分:3)
这取决于您需要对此数据执行的操作。如果您只需要线性处理一次,那么在内存中获取大文件的性能可能会更快。
但是,如果您需要对文件执行各种操作,而不是单个线性解析,我会将数据解析为轻量级数据库(如SQLite),然后对其进行操作。这样就可以保留所有文件的结构,并且文件上的所有后续操作都会更快。
答案 1 :(得分:1)
注册表访问非常复杂。您基本上是在阅读一个大型二叉树。类设计应该严重依赖于存储的数据结构。只有这样,您才能选择合适的班级设计。为了保持灵活性,你应该对REG_SZ,REG_EXPAND_SZ,DWORD,SubKey等基元进行建模.Don Syme在他的书“Expert F#”中有一个关于二进制组合二进制解析的很好的部分。基本思想是你的对象自己知道如何从二进制表示反序列化。当你有一个像这样结构的字节流
<页眉和GT; <节点1 />
<节点2> < directory1中>
< /节点2> < /页眉和GT;
从二进制读取器开始逐字节读取二进制对象。既然您知道首先必须是标题,您可以将其传递给标题对象
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的包装。
此致, Alois Kraus
为了支持从内存映射文件延迟加载,有意义的是不要将字节数组读入对象并稍后解析它,但更进一步并且只存储来自内存映射文件的内存块的偏移量和长度。稍后当实际访问对象时,您可以读取和反序列化数据。这样,您可以遍历整个文件并构建一个对象树,其中只包含偏移量和对内存映射文件的引用。这应该可以节省大量内存。