如何检查多个文件夹并删除具有唯一文件名的任何文件?

Posted

技术标签:

【中文标题】如何检查多个文件夹并删除具有唯一文件名的任何文件?【英文标题】:How do I check multiple folders and delete any files with unique file names? 【发布时间】:2021-11-17 07:49:21 【问题描述】:

我正在从检查系统上的多个摄像头捕获小部件的图像。如果检查不成功,则不会保存图像。图像以小部件的序列号命名。

所以我的文件夹结构可能看起来像

相机1 1.tif 2.tif 4.tif 相机2 2.tif 3.tif 4.tif 相机3 1.tif 2.tif 3.tif 4.tif

我希望能够删除所有三个文件夹中都不匹配的图像。我不介意两次运行该解决方案,一次在相机 1 和相机 2 之间,然后再次使用相机 2 和相机 3。

我希望只剩下以下文件夹结构。

相机1 2.tif 4.tif 相机2 2.tif 4.tif 相机3 2.tif 4.tif

每个文件夹中有大约 12,000 个文件供分析,可能有 2%-3% 的错误需要删除才能继续分析。

我不介意需要付款、python、命令行等的预打包解决方案。

非常感谢!

【问题讨论】:

没有downvote your question because no attempt was made,因为你是一个新的贡献者,但通常我们希望你至少提出一个honest attempt at the solution,然后然后问具体问题) 关于您的实施。 首先您必须阅读所有文件名。接下来,您应该使用此文件名创建带有 "1.tif":["Camera1", "Camera3"], "2.tif":[...] 等列表的字典,接下来您应该检查列表中哪些文件名的值少于 3 个,然后您可以从这些文件夹中删除这些文件名。 既然在内存中加载几个列表文件的数量不会引起问题,那么如何使用文件夹的内容创建3个集合,确定这三个集合的交集,然后删除原始列表中的那个交集。这样一来,您就剩下三组,可以准确地告诉您需要在每个文件夹中删除哪些文件。 【参考方案1】:

按照 cmets 的建议,下次您在 SO 上提出问题时,请先自己试一试,并询问任何问题 - 这样您可以了解更多信息。

这是一个开始,如下所示,下面的代码使用文件夹的内容创建 3 个集合,确定这三个集合的交集,然后从原始集合中删除该交集。结果会准确告诉您每个文件夹中需要删除哪些文件:

from pathlib import Path


def find_unmatched(dirs):
    # list the (file) contents of the folders
    contents = 
    for d in dirs:
        contents[d] = set(str(n.name) for n in Path(d).glob('*') if n.is_file())

    # decide what the folders have in common
    all_files = list(contents.values())
    common = all_files[0]
    for d_contents in all_files[1:]:
        common = common.intersection(d_contents)

    # create a dictionary that tells you what to remove
    return d: files - common for d, files in contents.items()


to_remove = find_unmatched(['photos/Camera1', 'photos/Camera2', 'photos/Camera3'])
print(to_remove)

结果(假设您的示例中的文件夹位于名为 photos 的文件夹中):

'photos/Camera1': '1.tif', 'photos/Camera2': '3.tif', 'photos/Camera3': '1.tif', '3.tif'

实际上删除文件是一些您可能自己弄清楚的代码。

【讨论】:

【参考方案2】:

如前所述,您应该自己努力解决问题,遇到困难时寻求帮助。不过,我现在有一些空闲时间,所以我写了一个完整的 Batch 解决方案:

@echo off
setlocal EnableDelayedExpansion

rem Process files in Camera1 folder and populate "F" array elements = 1
cd Camera1
for %%a in (*.tif) do set "F[%%~Na]=1"

rem Process files in Camera2 and *accumulate* files to "F" array
cd ..\Camera2
for %%a in (*.tif) do set /A "F[%%~Na]+=1"

rem Process files in Camera3 and accumulate files to "F" array
rem if counter == 3 then file is OK: remove "F" element
rem else: delete file
rem       if counter == 1: remove "F" element

cd ..\Camera3
for %%a in (*.tif) do (
   set /A "F[%%~Na]+=1"
   if !F[%%~Na]! equ 3 (
      set "F[%%~Na]="
   ) else (
      del %%a
      if !F[%%~Na]! equ 1 set "F[%%~Na]="
   )
)

rem Remove files of "F" array in both Camera1 and Camera2 folders, ignoring error messages
cd ..
(for /F "tokens=2 delims=[]" %%a in ('set F[') do (
   del Camera1\%%a.tif
   del Camera2\%%a.tif
)) 2>nul

请报告结果...

【讨论】:

嘿@Aacini,这就像一个魅力。从脚本中创建了三个同名文件夹并填充了工作的一个子集,运行未经编辑的脚本,它们都完美无缺。谢谢您的帮助!此外,在展示我以前的作品方面,我绝对吸取了教训!感谢您的耐心等待! 请注意,批处理文件存在大量环境变量的速度问题。使用您的 ~12000 个文件运行此程序并检查经过的时间。也许会花费太多时间,并且需要修改方法... 嘿@Aacini,解析 12K 文件大约需要 3 分钟。再次,非常感谢您的宝贵时间,工作得很好! 我可以请你帮个忙吗?你能用我这里的另一种方法(基于文件的方法)运行同一组文件并比较时间吗?这一点对我来说很重要。谢谢!【参考方案3】:

虽然方法很简单,但可能不是最快的:

@echo off
rem // Change into root directory:
pushd "%~dp0." && (
    rem // Outer loop through target directories:
    for /D %%J in ("Camera?") do (
        rem // Create temporary file with matching contents of current directory:
        dir /B /A:-D-H-S "%%~J\*.tif" > "%TEMP%\%%~nxJ.log"
        rem // Inner loop through target directories:
        for /D %%I in ("Camera?") do (
            rem // Avoid comparing current directory with itself:
            if /I not "%%~I"=="%%~J" (
                rem /* List these files inside of the directory of the inner loop where no
                rem    respective files inside of the directory of the outer loop are found: */
                for /F "delims= eol=|" %%K in ('
                    dir /B /A:-D-H-S "%%~I\*.tif" ^| findstr /L /I /V /G:"%TEMP%\%%~nxJ.log"
                ') do (
                    rem // Actually delete current file:
                    ECHO del "%%~I\%%K"
                )
            )
        )
        rem // Delete temporary file:
        del "%TEMP%\%%~nxJ.log"
    )
    rem // Return from root directory:
    popd
)
exit /B

关键是目标目录上的两个嵌套循环,以便相互比较,findstr command 用于从一个目录中过滤掉另一个目录中不存在的文件。

测试正确的输出后,删除大写的ECHO 命令

【讨论】:

【参考方案4】:

这个新方法是基于文本文件的,所以它应该比环境变量方法运行得更快。在 12000 行文件(6 次!)中搜索缺失名称的繁重任务由 findstr 命令执行。

这种方法也比较简单,可以匹配3个以上的文件夹。

@echo off
setlocal EnableDelayedExpansion

rem Get a list of directories and create temp files with their contents
set "directories="
for /D %%d in (Camera?) do (
   set "directories=!directories! %%d"
   dir /B "%%d\*.tif" > %%d.txt
)

rem Process the directories "d"
for %%d in (%directories%) do (

   rem Compare this directory "d" vs. the others "D"
   for %%D in (!directories:%%d=!) do (

      rem Remove files in this "d" that not exists in the other "D"
      (for /F %%f in ('findstr /V /G:%%D.txt %%d.txt') do del "%%d\%%f") 2>nul

   )

)

for %%d in (%directories%) do del %%d

【讨论】:

以上是关于如何检查多个文件夹并删除具有唯一文件名的任何文件?的主要内容,如果未能解决你的问题,请参考以下文章

检查具有相似名称的多个文件

如何在perl中验证具有给定文件扩展名的多个文件

如何创建具有从 csv 文件中的列表收集的唯一名称值的类的多个对象

Django:删除唯一约束并创建迁移

如何从存储库索引中删除具有给定模式的多个文件夹?

将多个 Excel 文件保存到具有唯一文件名的特定路径