如何快速查找添加/删除的文件?

mar*_*nus 11 java filesystems file

我正在编写一个小程序,它创建了我目录中所有文件的索引.它基本上遍历磁盘上的每个文件并将其存储到可搜索的数据库中,就像Unix的locate一样.问题是,由于我有大约一百万个文件,因此索引生成非常慢.

生成索引后,是否可以快速找到自上次运行以来在磁盘上添加或删除的文件?

编辑:我不想监视文件系统事件.我认为风险太高而无法实现同步,我更喜欢快速重新扫描,以便快速找到添加/删除文件的位置.也许目录上次修改日期或其他什么?

一个小基准

我刚做了一点基准.运行

dir /b /s M:\tests\  >c:\out.txt
Run Code Online (Sandbox Code Playgroud)

需要0.9秒,并提供我需要的所有信息.当我使用Java实现(很像这样)时,大约需要4.5秒.任何想法如何改善至少这种蛮力的方法?

相关文章:如何查看目录的子文件是否已更改

Ste*_*son 7

你能跳出java吗?

你可以简单地使用

dir /b /s /on M:\tests\  
Run Code Online (Sandbox Code Playgroud)

/按名称排序

如果你把它输出到out.txt

然后在上次以Java或批处理文件运行此文件时执行diff操作.在Dos中有类似的东西.你需要得到一个diff工具,在cygwin中的diff或者优秀的http://gnuwin32.sourceforge.net/packages/diffutils.htm

dir /b /s /on m:\tests >new.txt
diff new.txt archive.txt >diffoutput.txt
del archive.txt
ren new.txt archive.txt
Run Code Online (Sandbox Code Playgroud)

显然你也可以使用java diff类,但我认为接受的是shell命令几乎总是在文件列表操作中击败Java.


kro*_*old 6

不幸的是,没有标准的方法来监听java中的文件系统事件.这可能是在java7中出现的.

目前,您必须谷歌"java文件系统事件"并选择与您的平台匹配的自定义实现.


Aar*_*lla 4

我已经在我的工具 MetaMake 中完成了此操作。这是食谱:

  1. 如果索引为空,则将根目录添加到索引中,时间戳== dir.lastModified()-1。
  2. 查找索引中的所有目录
  3. 将索引中目录的时间戳与文件系统中的目录时间戳进行比较。这是一个快速的操作,因为您拥有完整路径(无需扫描所涉及的树中的所有文件/目录)。
  4. 如果时间戳已更改,则此目录已发生更改。重新扫描并更新索引。
  5. 如果在此步骤中遇到丢失目录,请从索引中删除子树
  6. 如果遇到现有目录,忽略它(将在步骤2中检查)
  7. 如果遇到新目录,请使用 timestamp == dir.lastModified()-1 添加它。确保在第 2 步中考虑到这一点。

这将使您能够有效地注意到新的和删除的文件。由于您在步骤 #2 中仅扫描已知路径,因此这将非常有效。文件系统不擅长枚举目录中的所有条目,但当您知道确切的名称时,它们会很快。

缺点:您不会注意到更改的文件。因此,如果您编辑文件,这不会反映在目录的更改中。如果您也需要此信息,则必须对索引中的文件节点重复上述算法。这次,您可以忽略新的/删除的文件,因为它们在目录上运行期间已被更新。

[编辑]扎克提到时间戳是不够的。我的回答是:没有其他办法可以做到这一点。对于目录来说,“大小”的概念是完全未定义的,并且随着实现的不同而发生变化。没有 API 可以让您注册“我希望收到对文件系统中某些内容进行的任何更改的通知”。有些 API 在您的应用程序处于活动状态时可以工作,但如果它停止或错过某个事件,那么您就会失去同步。

如果文件系统是远程的,情况会变得更糟,因为各种网络问题都可能导致您不同步。因此,虽然我的解决方案可能不是 100% 完美且防水,但它适用于除最构造的特殊情况之外的所有情况。这是唯一能走到这一步的解决方案。

现在有一种应用程序希望在进行修改后保留目录的时间戳:病毒或蠕虫。这显然会破坏我的算法,但它并不是为了防止病毒感染。如果你想防止这种情况发生,你必须采用完全不同的方法。

实现 Zach 想要的唯一其他方法是构建一个新的文件系统,将这些信息永久记录在某个地方,将其出售给 Microsoft,并等待几年(可能 10 或更长时间)直到每个人都使用它。