程序启动时同步文件系统和缓存数据

时间:2009-11-12 02:15:10

标签: c# algorithm sqlite caching filesystems

我有一个程序需要检索一些文件的一些数据(即一个目录及其中的所有文件和某些类型的子目录)。计算数据(非常)非常昂贵,因此我不是在程序启动时遍历文件系统并计算它,而是将数据缓存保存在SQLite数据库中,并使用FilesystemWatcher监视文件系统的更改。这在程序运行时很有用,但问题是如何在程序启动期间刷新/同步数据。如果文件已被添加(或更改 - 我认为我可以通过上次修改/大小检测到这一点),则需要在缓存中重新计算数据,如果文件已被删除,则需要从缓存中删除数据(因为接口遍历缓存而不是文件系统。)

所以问题是:做这个的好算法是什么?我能想到的一种方法是遍历文件系统并收集字典中所有文件的路径和最后修改/大小。然后我浏览数据库中的整个列表。如果没有匹配项,那么我从数据库/缓存中删除该项。如果匹配,则从字典中删除该项。然后字典包含其数据需要刷新的所有项目。这可能会有效,但是在每次启动时都会显得内存密集且耗时,所以我想知道是否有人有更好的想法?

如果重要:该程序是在Windows CLR 3.5上用C#编写的,使用SQLite for ADO.NET,可通过实体框架/ LINQ for ADO.NET访问。

3 个答案:

答案 0 :(得分:2)

Windows有一个更改日志机制,可以执行您想要的操作:您订阅了文件系统某些部分的更改,并且在启动时可以读取自上次读取后发生的更改列表。请参阅:http://msdn.microsoft.com/en-us/library/aa363798(VS.85).aspx

编辑:不幸的是,我认为它需要相当高的权限

答案 1 :(得分:2)

我们的应用程序是跨平台的C ++桌面应用程序,但具有非常相似的要求。以下是我所做的高级描述:

  • 在我们的SQLite数据库中有一个Files表,用于存储file_idnamehash(目前我们使用上次修改日期作为哈希值)和{{ 1}}。
  • 每个其他记录都会返回state。这使得在文件更改时很容易删除“脏”记录。

我们检查文件系统和刷新缓存的过程分为几个不同的步骤,以便于测试,并使我们更灵活地了解缓存何时发生( italics 中的名称是正是我碰巧选择了班级名称):

第一次启动时

  • 数据库为空。 Walker 以递归方式遍历文件系统并将条目添加到file_id表中。 Files设置为state
  • 接下来, Loader 遍历UNPROCESSED表,查找Files个文件。这些是传递给 Parser (它实际解析和插入数据)
  • 这需要一段时间,因此第一次启动可能会有点慢。

有一个很大的可测试性优势,因为您可以独立于加载/解析代码测试文件系统代码的行走。在随后的发布中,情况稍微复杂一些:

n + 1发布

  • Scrubber 遍历UNPARSED表,查找已删除的文件和已修改的文件。如果文件存在但已被修改,则会将Files设置为state,如果文件不再存在,则将DIRTY设置为。{/ li>
  • Deleter (不是最原始的名称)然后遍历DELETED表,查找FilesDIRTY个文件。它删除其他相关记录(通过DELETED相关)。移除相关记录后,原始file_id记录将被删除或重新设置为File
  • Walker 然后遍历文件系统以获取新文件。
  • 最后 Loader 加载所有state=UNPARSED个文件

目前“最糟糕的情况”(每个文件都有变化)非常罕见 - 所以我们每次启动应用程序时都这样做。但是通过将这个过程分解为这些步骤,我们可以轻松地将实现扩展到:

  • Scrubber / Deleter 可以重构为将脏记录留在原位,直到新的 加载数据(因此当新数据缓存到数据库中时,应用程序“继续工作”)
  • Loader 可以在主应用程序的空闲时间内加载/解析后台线程
  • 如果您提前了解数据文件,可以为文件分配“权重”并立即加载/解析真正重要的文件,并将不太重要的文件排队等待以后处理。

只是一些想法/建议。希望他们帮忙!

答案 2 :(得分:1)

首先想到的是创建一个单独的小应用程序,它总是运行(可能是一个服务),并在文件系统中创建一种“日志”变更(不需要使用SQLite,只需将它们写入文件)。然后,当主应用程序启动时,它可以查看日志并确切知道更改了什么(不要忘记之后清除日志: - )。

但是,如果由于某种原因你不能接受,那么让我们试着看一下原来的问题。

首先,你必须接受,在最糟糕的情况下,当所有文件都发生变化时,需要遍历整个树。 可能(虽然不一定会)需要很长时间。一旦你意识到这一点,你必须考虑在后台完成工作,而不会阻止应用程序。

其次,如果你必须对每个只知道如何制作的文件做出决定,那么除了浏览所有文件之外别无他法。

换句话说,你可能会说问题本质上是复杂的(并且任何给定的问题都无法通过比问题本身更简单的算法来解决。)

因此,您唯一的希望是通过使用调整和黑客来减少搜索空间。我有两个想法。

首先,最好分别为每个文件查询数据库,而不是首先构建所有文件的字典。如果在数据库的文件路径列上创建索引,它应该更快,当然也可以减少内存密集。

其次,你根本不需要查询数据库:-) 只需存储应用程序上次运行的确切时间(在.settings文件中?)并检查每个文件以查看它是否比该时间更新。如果是,你知道它已经改变了。如果不是,你知道你上次发现了它的变化(使用你的FileSystemWatcher)。

希望这会有所帮助。玩得开心。