提问者:小点点

比较DB查询结果和文件系统的文件路径的最有效方法


我有一个存储文件路径的数据库,例如:

SELECT filepath FROM content
-- results: 
-- D:\eb3097ef-f3d9-463f-bda5-d3c737acf767\7b34d48e-f176-11ec-8ea0-0242ac120002
-- D:\eb3097ef-f3d9-463f-bda5-d3c737acf767\7b34d48e-f176-11ec-8ea0-0242ac120003
-- D:\b4198a77-4c66-4edb-bef9-548546c0e01f\2e565c87-861f-46a8-9c75-e5861f2b087f\..
...

所有目录和文件名都是UUID(36位)。我知道包含所有文件的根目录,必须检查

  1. db查询产生的所有文件都存在于根目录中
  2. 根目录中有任何文件,但数据库中没有

所以我基本上必须将文件系统与数据库进行比较,反之亦然。我需要确切地知道某个文件丢失的位置(db或fs),而不仅仅是它丢失的事实。

到目前为止,我的解决方案很简单。手动将所有db查询结果导出到txt文件,然后使用PowerShellgci在根目录中循环。之后,我将两个输出解析为集合。通用。HashSet[string],最后对它们执行了SymmetricExceptFor。这实际上是不错的性能(约10-15分钟。对于总容量约为1TB/CPU使用率约为40%的1.700.000个文件),但尝试2TB会使系统屈服。

实现这一目标的最佳和最有效的方法是什么?首选基于Java的解决方案,但C#甚至PS也可以。


共1个答案

匿名用户

1TB文件意味着什么?据推测,“未知数量的文件,其大小总计约为1 TB”,但这完全无关,唯一相关的问题是有多少文件。

最快的一般原则:

  1. 从数据库中获取所有文件路径,将其删除到最小值(即如果它们都以D:\data\开头,则将其删除)。
  2. 排序。
  3. 从磁盘获取所有filepath(即ls的结果),剥离。
  4. 排序。
  5. 同时循环两次,在循环时生成不匹配列表。

步骤1为O(n),步骤2为O(n log n),步骤3为O(m),步骤4为O(m log m),步骤5为O(max(n, m))。

假设nm的大小相似,那就是O(3n 2n*log(n)),这就是O(n log n),从算法上讲,我认为你做得不好;即使您有数百万个文件,这也应该很好。

然而,这有两个方面的表现取决于外部因素,并且可能非常重要:

  1. “列出所有文件”的速度有多快?一旦有了一个包含数百万个文件的目录,速度就会非常慢:文件系统通常不会很快做到这一点,如果是的话,查询这些文件的各种API通常都是无效的。我想是文件。newDirectoryStream速度很快,但我不能为您保证。有可能是一个低级的bash-c ls

想想看,在白板或纸上垂直写下这两个列表(第1行:Apple,第2行:Banana等),然后将第二个列表垂直放在它旁边(因此两个Apple都在同一行)。

[苹果、香蕉、樱桃、金桔、辣椒、梨]

【苹果、香蕉、金桔、橙子、胡椒、梨】

现在想象一下人们会怎么做。这很简单:做一个小标记(例如一张撕下来的纸);这是“指针”,为每个列表创建一个指针。将“指针”放在每个列表的第一个条目上。

现在你的算法很简单:

>

  • 如果两个指针都指向同一个字符串,则什么都不做(该条目在两者中,因此已经同步,无需操作)-只需将两个指针向下推进到下一个条目。

    否则,检查两个字符串中哪个是“较低的”(排序在另一个下面)。那个是唯一的——相应地注册,然后只前进那个指针。

    真的是这样-您只需要添加一些额外的逻辑来处理如果两个指针中的一个在末尾(这意味着另一个必然是唯一的)会发生什么,并添加代码,如果两个指针都在末尾,您就完成了算法。

    在本例中,您将跳过苹果和香蕉,然后。。

    樱桃比金桔低,所以樱桃在第一个列表中是独一无二的。然后你只需前进那个指针。接下来比较金桔和金桔,然后将两者都推进,然后注意到橙色在胡椒下面,所以橙色是唯一的,然后算法结束,得出结论,列表1有一个唯一的樱桃,列表2有一个唯一的橙色。全部输入<代码>O(n)。