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

Java 如何快速查找添加/删除的文件?,java,file,filesystems,Java,File,Filesystems,我正在写一个小程序,创建我目录中所有文件的索引。它基本上迭代磁盘上的每个文件,并将其存储到可搜索的数据库中,很像Unix的locate。问题是,索引生成相当慢,因为我有大约一百万个文件 生成索引后,是否有一种快速方法可以确定自上次运行以来磁盘上添加或删除了哪些文件 编辑:我不想监视文件系统事件。我认为失去同步的风险太高了,我更喜欢像快速重新扫描那样快速找到文件添加/删除的位置。可能是目录最后修改的日期还是什么 一个小基准 我只是做了一个小基准。运行 dir /b /s M:\tests\ &g

我正在写一个小程序,创建我目录中所有文件的索引。它基本上迭代磁盘上的每个文件,并将其存储到可搜索的数据库中,很像Unix的locate。问题是,索引生成相当慢,因为我有大约一百万个文件

生成索引后,是否有一种快速方法可以确定自上次运行以来磁盘上添加或删除了哪些文件

编辑:我不想监视文件系统事件。我认为失去同步的风险太高了,我更喜欢像快速重新扫描那样快速找到文件添加/删除的位置。可能是目录最后修改的日期还是什么

一个小基准 我只是做了一个小基准。运行

dir /b /s M:\tests\  >c:\out.txt
只需0.9秒,就能提供我需要的所有信息。当我使用Java实现()时,大约需要4.5秒。有没有办法至少改进这种暴力手段


相关帖子:

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


现在,您必须搜索“java文件系统事件”,并选择与您的平台匹配的自定义实现。

加快速度的一种方法是,只需迭代目录并检查上次修改的时间,以查看自上次索引以来目录的内容是否发生了更改,如果他们只是在目录上做了一个普通的扫描,然后看看你是否能找到变化的地方。我不知道它的可移植性有多好,但它改变了层次结构,在Linux系统上传播(可能依赖于文件系统),因此您可以从根目录开始,然后向下运行,当您找到一个未更改的目录时停止运行。

文件日期方法可能不是最好的方法。例如,如果从备份中还原文件。也许在索引期间,您可以存储文件内容的MD5散列。但是,您可能需要进行一些性能基准测试,看看性能是否可以接受

我听说这项任务很难有效完成。我相信微软如果简单的话也会实现类似于Windows的工具,特别是在HD:s不断增长的今天。

我还没有检查实现或性能,但commons io有一个方法。这可能值得一试。

鉴于我们不想监视文件系统事件,我们是否可以跟踪每个文件的
(名称、大小、时间、校验和)
?文件校验和(或加密哈希,如果您愿意)的计算将成为瓶颈。您可以在初始运行时只计算一次,然后仅在以后需要时(例如,当文件与其他三个属性匹配时)重新计算。当然,如果我们只想跟踪文件名,而不想跟踪文件内容,就不必为此费心了

您提到,与“
dir/s
”相比,您的Java实现(类似于)非常慢。我认为有两个原因:

  • 它天生就是慢的。有关更多信息,请参阅前面的问题“”和Java RFE“”。很明显,这一缺陷已被解决,即将推出

  • 您是否使用递归遍历目录?如果是这样,请尝试一种非递归方法,例如在堆栈上/下推/弹出要访问的目录。我的建议是,这种改进可能相当显著

  • 怎么样:

    (由于该版本一次只能读取一个字符,因此有很大的改进余地: 您可以选择更好的版本以更快地读取流)

    你用以下作为论据:

    "dir /b /s M:\tests\"
    
    如果这将用于正在运行的应用程序(而不是作为一个独立的应用程序),您可以将JVM的“预热”时间打折,这大约是1-2秒,具体取决于您的硬件


    您可以尝试一下,看看它有什么影响。

    我已经在我的工具MetaMake中完成了这项工作。以下是菜谱:

  • 如果索引为空,请使用timestamp==dir.lastModified()-1将根目录添加到索引中
  • 查找索引中的所有目录
  • 比较索引中目录的时间戳与文件系统中的时间戳。这是一个快速的操作,因为您拥有完整的路径(不扫描相关树中的所有文件/目录)
  • 如果时间戳已更改,则此目录中有更改。重新扫描它并更新索引
  • 如果在此步骤中遇到缺少目录,请从索引中删除子树
  • 如果遇到现有目录,请忽略它(将在步骤2中进行检查)
  • 如果遇到新目录,请使用timestamp==dir.lastModified()-1添加它。确保在第2步中考虑到它
  • 这将使您能够有效地注意到新文件和已删除的文件。由于在步骤2中只扫描已知路径,因此这将非常有效。文件系统不擅长枚举目录中的所有条目,但当您知道确切的名称时,它们的速度很快

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

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

    如果文件系统是远程的,情况会变得更糟,因为各种
    "dir /b /s M:\tests\"
    
    dir /b /s /on M:\tests\  
    
    dir /b /s /on m:\tests >new.txt
    diff new.txt archive.txt >diffoutput.txt
    del archive.txt
    ren new.txt archive.txt