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

     2023-02-16     148

关键词:

【中文标题】如何快速找到添加/删除的文件?【英文标题】:How to quickly find added / removed files? 【发布时间】:2009-01-26 13:19:13 【问题描述】:

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

一旦我生成了索引,是否有一种快速的方法可以找出自上次运行以来磁盘上添加或删除了哪些文件?

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

一个小基准

我只是做了一个小基准测试。跑步

dir /b /s M:\tests\  >c:\out.txt

只需 0.9 秒,即可为我提供所需的所有信息。当我使用 Java 实现 (much like this) 时,大约需要 4.5 秒。任何想法如何至少改进这种蛮力方法?

相关帖子:How to see if a subfile of a directory has changed

【问题讨论】:

我们是否可以假设我们只对添加和删除的文件感兴趣,即我们只索引文件名,其他所有内容(例如大小、上次修改时间、加密哈希)都无关紧要? 我们可以假设它仅适用于 Windows 平台吗?您可以使用 Microsoft 提供的索引服务(而不是自己滚动)吗? 另外,为什么您认为监视文件系统事件会存在不同步的风险?我不知道在 Java 中,但在 C#/.NET 中,您可以创建事件侦听器,在添加或删除给定路径下的文件或目录时触发,并且它 100% 的时间都可以工作...... @Coder,因为这样就要求应用程序一直在运行。也许最好像 Aaron Digulla 的回答那样快速扫描目录更改,然后在应用程序运行时使用事件侦听器。 【参考方案1】:

你能跳出java吗?

你可以简单地使用

dir /b /s /on M:\tests\  

/on 按名称排序

如果你把它输出到 out.txt

然后对您上次在 Java 或批处理文件中运行此文件进行比较。在 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

显然您也可以使用 java diff 类,但我认为可以接受的是,shell 命令几乎总是会在文件列表操作中胜过 Java。

【讨论】:

【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

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

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

[EDIT] Zach 提到时间戳是不够的。我的回答是:根本没有其他方法可以做到这一点。对于目录和从实施到实施的变化,“大小”的概念是完全未定义的。没有 API 可以在其中注册“我希望在对文件系统中的某些内容进行任何更改时收到通知”。有些 API 可以在您的应用程序处于活动状态时工作,但如果它停止或错过某个事件,那么您就不同步了。

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

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

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

【讨论】:

到目前为止,这是最好的答案。您知道这是文件系统特有的功能,还是可以在任何地方使用它? 它适用于 Unix 文件系统和 Windows。我没有用 HFS 测试过,但如果有任何问题,我会感到惊讶。 @Aaron:这种方法是否假定目录最后修改的时间戳在添加/删除文件时会发生变化?如果在外部修改目录时间戳会发生什么,例如通过“触摸”? (续) (cont'd) 此外,时间戳的使用在某些文件系统上可能不够好,例如FAT 只有 2 秒的精度,因此快速发生的变化可能不会被发现。 @Zach:然后你就白读了目录。但是几乎没有损坏,因为您只会读取该单个目录。【参考方案4】:

您可以加快速度的一种方法是遍历目录并检查上次修改时间以查看自上次索引以来目录的内容是否发生了变化,以及他们是否刚刚对目录进行了正常扫描然后看看你是否能找到变化的地方。我不知道这将是多么可移植,但是它改变层次结构会在 Linux 系统上传播(可能取决于文件系统),因此您可以从根目录开始并向下工作,当您点击一个目录时停止'没有改变

【讨论】:

您必须检查每个目录,因为 Windows 不会传播,但这仍然会更快,因为您知道上次索引运行的所有路径。我以前做过这个,它有效。加速是巨大的!【参考方案5】:

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

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

    File.listFiles() 本身就很慢。有关更多信息,请参阅这个较早的问题“Is there a workaround for Java’s poor performance on walking huge directories?”和这个 Java RFE“File.list(FilenameFilter) is not effective for huge directories”。 NIO.2 显然解决了这个缺点,即将推出。

    您是否正在使用递归遍历您的目录?如果是这样,请尝试使用非递归方法,例如在堆栈上/从堆栈上推送/弹出要访问的目录。我的limited personal experience 表明改进可能非常显着。

【讨论】:

【参考方案6】:

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

【讨论】:

我写了一些类似的东西来查找我硬盘上的重复文件。 MD5 很慢。我尝试对程序进行多线程处理,但它只是让我的计算机陷入了爬行。 计算 MD5 哈希需要读取整个文件。如果您正在寻找的是性能,那并不是很好...... 确实如此。这就是为什么我建议进行基准测试以检查性能是否可以接受。任何想法如何处理从备份中恢复的文件?【参考方案7】:

我听说这项任务很难有效地完成。我敢肯定,如果它很容易,MS 会实现与 Windows 类似的工具,尤其是在 HD:s 越来越多的今天。

【讨论】:

【参考方案8】:

来点什么like this:

private static String execute( String command ) throws IOException   
    Process p = Runtime.getRuntime().exec( "cmd /c " + command );
    InputStream i = p.getInputStream();
    StringBuilder sb = new StringBuilder();
    for(  int c = 0 ; ( c =  i.read() ) > -1  ; ) 
        sb.append( ( char ) c );
    
    i.close();
    return sb.toString();

(那里有 很多 改进的空间,因为该版本一次读取一个字符: 您可以选择更好的版本from here 以更快地读取流)

你使用作为参数:

"dir /b /s M:\tests\"

如果这将用于正在运行的应用程序(而不是作为独立应用程序),您可以忽略 JVM 的“预热”时间,这取决于您的硬件大约 1 到 2 秒。

你可以试试看有什么影响。

【讨论】:

我已经尝试过这种方式,但是 dir 的愚蠢排序使其在扫描层次结构时难以使用。 @martinus: mmhh 在以下几行中: String s = getFileList(); Arrays.sort(s.split(lineSep));也许?【参考方案9】:

尝试使用 git。版本控制软件就是针对这类问题的,git以速度着称;它专为快速处理本地文件而设计。 'git diff --name-status' 会让你得到你想要的。

【讨论】:

我想索引包含数百万个文件的大型文件系统【参考方案10】:

我没有检查实现或性能,但是 commons-io 有一个listFiles() 方法。可能值得一试。

【讨论】:

它只是调用 Java 的列表文件

快速访问的内容出现在了桌面上如何去掉?

...是之前不小心从快速访问去掉再重新添加回来后就这样了如何关闭快速访问功能:1.关闭“开始”菜单中最近使用的文件:个性化设置-开始,右侧关闭2.关闭此电脑中最近使用过的文件:打开此电脑>;视图>;选项>;更改文... 查看详情

如何删除iso封装中的软件

...SP3装机系统里面有很多垃圾软件,皮皮、酷我音乐盒等,如何从ISO中将这些软件删除?这样我就不用给别人装机的时候一次次去删除了。删除ISO文件并不难,这里还延伸了添加的方法,让添加和删除都非常轻松容易看教程:1、... 查看详情

如何手动添加和删除windows服务

你好!打开“计算机”,点击上端的“卸载或更改程序”,然后在打开的页面中点击左侧的“打开或关闭WINDOWS功能”,在列表中找到需要添加的程序或服务,勾选后点确定即可,如果要卸载,那么去掉前面的勾选后确定。参考... 查看详情

如何将文件添加到忽略列表中

CleanMyMac3扫描大型和旧文件(举例)结束后,点击“查看详情”,查看所有即将删除的文件,找到需要忽略的文件并选中,然后点击“文件”——“添加到忽略列表中”。出现对话框“您已经将一个项目添加到CleanMyMac的忽略列表... 查看详情

快速访问中的ftp怎样删除

Win10系统。在资源管理器的快速访问中添加了ftp://public.sjtu.edu.cn/。现在不想要了,请问应该怎样删除?右键快速访问中的ftp文件夹只有“展开”,无法删除。选中要删除的ftp,再选一个文件夹,就能在右键菜单看到取消固定的选... 查看详情

mysql如何删除密码

我的密码没忘记,但是我想下次登陆免密码,应该怎么设置参考技术Awindows找到my.ini文件linux找到my.cnf文件修改文件内容在[mysqld]下添加skip-grant-tables如图,保存文件重启mysqlservicemysqldrestart 查看详情

win10此电脑快速访问怎么删除

...搜索选项】,3、找到隐私,点击清除。取消勾选【在“快速访问”中显示最近使用文件】和【在“快速访问”中显示常用文件夹】。4、设置完成后点击应用即可。参考技术A1、点击电脑桌面【我的电脑】,进入【我的电脑】,... 查看详情

如何找到并恢复已删除的文件

】如何找到并恢复已删除的文件【英文标题】:Howtolocateandrecoveradeletedfile【发布时间】:2012-04-0120:43:15【问题描述】:在过去的某个阶段,我有一个受Mercurial源代码控制的“foo.txt”。不过现在已经被删除了。当我不知道文件被... 查看详情

pdf添加书签的快速方法

...接触到一份pdf文档时,如果需要给PDF添加书签,我们应该如何操作呢?感兴趣的小伙伴们继续往下阅读吧。操作软件:迅捷PDF编辑器软件地址:https://www.xunjiepdf.com/editor1、首先我们需要找到一款可以给PDF文档添加书签的软件,我... 查看详情

如何在 WinRT 8.1 中使用 SharpCompress 删除/添加和输入 zip 文件

】如何在WinRT8.1中使用SharpCompress删除/添加和输入zip文件【英文标题】:Howtoremove/addandentryinzipfileusingSharpCompressinWinRT8.1【发布时间】:2014-04-2823:38:19【问题描述】:正如我的标题所说的那样简单,没有找到任何代码示例,我无法... 查看详情

如何快速删除mac下没用的other文件

第一步:打开想要批量删除的文件所在的文件夹第二步:使用Command+A,选择所有的文件夹,当然也可以使用ctrl键一个一个选择想要删除的文件夹第三步:选择“移到废纸篓”,就完成了文件夹批量删除的操作参考技术A推荐DiskInv... 查看详情

win11/win10彻底删除系统“快速访问”中自动添加的文件夹-不再自动添加

...11任务栏透明效果_Rudon滨海渔村的博客-CSDN博客_translucenttb如何设置中文效果图translucentTB汉化菜单win11任务栏透明实现办法下载安装translucentTBMoretranslucenttb中文设置教程答:translucenttb原版是没有中文的,要下载汉化版才行... 查看详情

如何删除sqlserver数据库

SQLServer正常情况下可以通过添加删除将其卸载,但有时可能会出现一些不可遇见的原因,导致其不能自动卸载,就需要手工卸载,在手工卸载前要注意做好数据的备份工作,以便于以后做还原,卸载SQLServer包括两个方面:第一,程序文件和... 查看详情

如何在项目提交历史中找到已删除的文件?

】如何在项目提交历史中找到已删除的文件?【英文标题】:Howtofindadeletedfileintheprojectcommithistory?【发布时间】:2011-11-0410:25:34【问题描述】:曾几何时,我的项目中有一个文件,我现在希望能够得到它。问题是:我不知道我什... 查看详情

快速从音频文件中删除音频通道

】快速从音频文件中删除音频通道【英文标题】:Removingaudiochannelsfromaudiofileswift【发布时间】:2019-02-0412:58:26【问题描述】:我需要从音频文件中删除特定的音频通道,并将其保存为单声道文件。我发现可以使用AVAudioEngine或Audio... 查看详情

在 Swift 中添加目标 c 文件后,快速编译器错误“找到了这个候选者”

】在Swift中添加目标c文件后,快速编译器错误“找到了这个候选者”【英文标题】:swiftcompilererror"foundthiscandidate"afteraddingobjectivecfilesinSwift【发布时间】:2018-04-3006:11:25【问题描述】:我在我的swift项目中创建了桥接头,... 查看详情

在 Swift 中添加目标 c 文件后,快速编译器错误“找到了这个候选者”

】在Swift中添加目标c文件后,快速编译器错误“找到了这个候选者”【英文标题】:swiftcompilererror"foundthiscandidate"afteraddingobjectivecfilesinSwift【发布时间】:2018-04-3006:11:25【问题描述】:我在我的swift项目中创建了桥接头,... 查看详情

win10无法取消快速访问固定

...里找到文件:f01b4d95cf55d32a.automaticDestinations-ms删除它后,快速访问栏就全部删除了,可以重新添加快速访问。 查看详情