我有一个程序需要检索一些文件的一些数据(即一个目录及其中的所有文件和某些类型的子目录)。计算数据(非常)非常昂贵,因此我不是在程序启动时遍历文件系统并计算它,而是将数据缓存保存在SQLite数据库中,并使用FilesystemWatcher监视文件系统的更改。这在程序运行时很有用,但问题是如何在程序启动期间刷新/同步数据。如果文件已被添加(或更改 - 我认为我可以通过上次修改/大小检测到这一点),则需要在缓存中重新计算数据,如果文件已被删除,则需要从缓存中删除数据(因为接口遍历缓存而不是文件系统。)
所以问题是:做这个的好算法是什么?我能想到的一种方法是遍历文件系统并收集字典中所有文件的路径和最后修改/大小。然后我浏览数据库中的整个列表。如果没有匹配项,那么我从数据库/缓存中删除该项。如果匹配,则从字典中删除该项。然后字典包含其数据需要刷新的所有项目。这可能会有效,但是在每次启动时都会显得内存密集且耗时,所以我想知道是否有人有更好的想法?
如果重要:该程序是在Windows CLR 3.5上用C#编写的,使用SQLite for ADO.NET,可通过实体框架/ LINQ for ADO.NET访问。
答案 0 :(得分:2)
Windows有一个更改日志机制,可以执行您想要的操作:您订阅了文件系统某些部分的更改,并且在启动时可以读取自上次读取后发生的更改列表。请参阅:http://msdn.microsoft.com/en-us/library/aa363798(VS.85).aspx
编辑:不幸的是,我认为它需要相当高的权限答案 1 :(得分:2)
我们的应用程序是跨平台的C ++桌面应用程序,但具有非常相似的要求。以下是我所做的高级描述:
Files
表,用于存储file_id
,name
,hash
(目前我们使用上次修改日期作为哈希值)和{{ 1}}。state
。这使得在文件更改时很容易删除“脏”记录。我们检查文件系统和刷新缓存的过程分为几个不同的步骤,以便于测试,并使我们更灵活地了解缓存何时发生( italics 中的名称是正是我碰巧选择了班级名称):
第一次启动时
file_id
表中。 Files
设置为state
。UNPROCESSED
表,查找Files
个文件。这些是传递给 Parser (它实际解析和插入数据)有一个很大的可测试性优势,因为您可以独立于加载/解析代码测试文件系统代码的行走。在随后的发布中,情况稍微复杂一些:
n + 1发布
UNPARSED
表,查找已删除的文件和已修改的文件。如果文件存在但已被修改,则会将Files
设置为state
,如果文件不再存在,则将DIRTY
设置为。{/ li>
DELETED
表,查找Files
和DIRTY
个文件。它删除其他相关记录(通过DELETED
相关)。移除相关记录后,原始file_id
记录将被删除或重新设置为File
state=UNPARSED
个文件目前“最糟糕的情况”(每个文件都有变化)非常罕见 - 所以我们每次启动应用程序时都这样做。但是通过将这个过程分解为这些步骤,我们可以轻松地将实现扩展到:
只是一些想法/建议。希望他们帮忙!
答案 2 :(得分:1)
首先想到的是创建一个单独的小应用程序,它总是运行(可能是一个服务),并在文件系统中创建一种“日志”变更(不需要使用SQLite,只需将它们写入文件)。然后,当主应用程序启动时,它可以查看日志并确切知道更改了什么(不要忘记之后清除日志: - )。
但是,如果由于某种原因你不能接受,那么让我们试着看一下原来的问题。
首先,你必须接受,在最糟糕的情况下,当所有文件都发生变化时,将需要遍历整个树。 可能(虽然不一定会)需要很长时间。一旦你意识到这一点,你必须考虑在后台完成工作,而不会阻止应用程序。
其次,如果你必须对每个只知道如何制作的文件做出决定,那么除了浏览所有文件之外别无他法。
换句话说,你可能会说问题本质上是复杂的(并且任何给定的问题都无法通过比问题本身更简单的算法来解决。)
因此,您唯一的希望是通过使用调整和黑客来减少搜索空间。我有两个想法。
首先,最好分别为每个文件查询数据库,而不是首先构建所有文件的字典。如果在数据库的文件路径列上创建索引,它应该更快,当然也可以减少内存密集。
其次,你根本不需要查询数据库:-) 只需存储应用程序上次运行的确切时间(在.settings文件中?)并检查每个文件以查看它是否比该时间更新。如果是,你知道它已经改变了。如果不是,你知道你上次发现了它的变化(使用你的FileSystemWatcher)。
希望这会有所帮助。玩得开心。