使用Coldfusion(递归)搜索文件夹中的重复照片?

使用Coldfusion(递归)搜索文件夹中的重复照片?,coldfusion,duplicates,Coldfusion,Duplicates,在移动和备份我的照片集几次之后,我有几张重复的照片,不同的文件名分散在我的PC上的不同文件夹中。因此我想我应该写一个快速的CF(9)页面来查找重复的照片(然后可以稍后添加代码以允许我删除它们) 我有几个问题:- 目前,我只是使用文件大小来匹配图像文件,但我认为匹配EXIF数据或匹配图像文件二进制的哈希值更可靠 我拼凑的代码有点有用,但如何在web根目录之外进行搜索呢 有更好的办法吗 p #名称[i]##目录[i]# 没有找到重复的JPG 我建议将检查代码拆分为只接受文件名的函数 然后使用全局结

在移动和备份我的照片集几次之后,我有几张重复的照片,不同的文件名分散在我的PC上的不同文件夹中。因此我想我应该写一个快速的CF(9)页面来查找重复的照片(然后可以稍后添加代码以允许我删除它们)

我有几个问题:-

  • 目前,我只是使用文件大小来匹配图像文件,但我认为匹配EXIF数据或匹配图像文件二进制的哈希值更可靠

  • 我拼凑的代码有点有用,但如何在web根目录之外进行搜索呢

  • 有更好的办法吗

  • p

    
    #名称[i]#
    #目录[i]# 没有找到重复的JPG
    我建议将检查代码拆分为只接受文件名的函数

    然后使用全局结构检查重复项,键为“size”或“size\u hash”,值可以是一个数组,该数组将包含与该键匹配的所有文件名

    对所有不同目录中的所有jpeg文件运行该函数,然后扫描结构并报告其数组中包含多个文件的所有条目


    如果您想在webroot之外显示图像,可以通过

    提供图像,这是一项非常有趣的任务,因此我决定尝试一下

    首先,我在装有4GB内存、2x2.26Ghz CPU和SSD的笔记本电脑上的一些测试结果:1143个图像,总计263.8MB

    ACF9:8个副本,耗时约2.3秒

    Railo 3.3:8个副本,耗时约2.0秒(耶!)

    我使用了来自的很棒的技巧来选择最好的散列选项

    下面是我所做的:

    <cfsetting enablecfoutputonly="true" />
    
    <cfset ticks = getTickCount() />
    
    <!--- this is great set of utils from Apache --->
    <cfset digestUtils = CreateObject("java","org.apache.commons.codec.digest.DigestUtils") />
    
    <!--- cache containers --->
    <cfset checksums = {} />
    <cfset duplicates = {} />
    
    <cfdirectory
        action="list"
        name="images"
        directory="/home/trovich/images/"
        filter="*.png|*.jpg|*.jpeg|*.gif"
        recurse="true" />
    
    <cfloop query="images">
    
        <!--- change delimiter to \ if you're on windoze --->
        <cfset ipath = images.directory & "/" & images.name />
    
        <cffile action="readbinary" file="#ipath#" variable="binimage" />
    
        <!---
            This is slow as hell with any encoding!
            <cfset checksum = BinaryEncode(binimage, "Base64") />
         --->
    
        <cfset checksum = digestUtils.md5hex(binimage) />
    
        <cfif StructKeyExists(checksums, checksum)>
    
            <!--- init cache using original on 1st position when duplicate found --->
            <cfif NOT StructKeyExists(duplicates, checksum)>
                <cfset duplicates[checksum] = [] />
                <cfset ArrayAppend(duplicates[checksum], checksums[checksum]) />
            </cfif>
    
            <!--- append current duplicate --->
            <cfset ArrayAppend(duplicates[checksum], ipath) />
    
        <cfelse>
    
            <!--- save originals only into the cache --->
            <cfset checksums[checksum] = ipath />
    
        </cfif>
    
    </cfloop>
    
    <cfset time = NumberFormat((getTickcount()-ticks)/1000, "._") />
    
    
    <!--- render duplicates without resizing (see options of cfimage for this) --->
    
    <cfoutput>
    
    <h1>Found #StructCount(duplicates)# duplicates, took ~#time# s</h1>
    
    <cfloop collection="#duplicates#" item="checksum">
    <p>
        <!--- display all found paths of duplicate --->
        <cfloop array="#duplicates[checksum]#" index="path">
            #HTMLEditFormat(path)#<br/>
        </cfloop>
        <!--- render only last duplicate, they are the same image any way --->
        <cfimage action="writeToBrowser" source="#path#" />
    </p>
    </cfloop>
    
    </cfoutput>
    
    
    找到#StructCount(重复项)#重复项,花费了#时间#
    
    #HTMLEditFormat(路径)#

    显然,您可以轻松地使用
    duplicates
    array来查看结果和/或运行一些清理作业


    玩得开心

    +1同样,这将确定哈希比较部分,谢谢Sergii。如何对其进行修改以处理同一图像/文件的2个以上副本?目前,如果您有3个相同的副本,那么您的代码将标识2个副本。另外,如何在web根目录之外显示图像预览?@Saul请检查更新的代码示例,我对其进行了一些修改。相同图像的所有实例现在都分组了,我同意这对于分析更方便。图像输出非常简单,但代价是图像以原始大小显示——对于大图像和/或少量图像,这将是非常慢的。。文件IO和操作系统级别的散列将更快更容易?@Henry:同意,但做操作系统级别散列的正确方法是什么?提供一个例子。@Henry这取决于您想要什么:根据您的个人需要解决任务,并享受CFML带来的乐趣(顺便说一句,我认为使用ApacheLib进行哈希运算非常快,但渲染不是),或者尽可能高效地解决任务。为了第二个目的,我会使用一个很好的现有工具,比如(Ubuntu)。
    <cfsetting enablecfoutputonly="true" />
    
    <cfset ticks = getTickCount() />
    
    <!--- this is great set of utils from Apache --->
    <cfset digestUtils = CreateObject("java","org.apache.commons.codec.digest.DigestUtils") />
    
    <!--- cache containers --->
    <cfset checksums = {} />
    <cfset duplicates = {} />
    
    <cfdirectory
        action="list"
        name="images"
        directory="/home/trovich/images/"
        filter="*.png|*.jpg|*.jpeg|*.gif"
        recurse="true" />
    
    <cfloop query="images">
    
        <!--- change delimiter to \ if you're on windoze --->
        <cfset ipath = images.directory & "/" & images.name />
    
        <cffile action="readbinary" file="#ipath#" variable="binimage" />
    
        <!---
            This is slow as hell with any encoding!
            <cfset checksum = BinaryEncode(binimage, "Base64") />
         --->
    
        <cfset checksum = digestUtils.md5hex(binimage) />
    
        <cfif StructKeyExists(checksums, checksum)>
    
            <!--- init cache using original on 1st position when duplicate found --->
            <cfif NOT StructKeyExists(duplicates, checksum)>
                <cfset duplicates[checksum] = [] />
                <cfset ArrayAppend(duplicates[checksum], checksums[checksum]) />
            </cfif>
    
            <!--- append current duplicate --->
            <cfset ArrayAppend(duplicates[checksum], ipath) />
    
        <cfelse>
    
            <!--- save originals only into the cache --->
            <cfset checksums[checksum] = ipath />
    
        </cfif>
    
    </cfloop>
    
    <cfset time = NumberFormat((getTickcount()-ticks)/1000, "._") />
    
    
    <!--- render duplicates without resizing (see options of cfimage for this) --->
    
    <cfoutput>
    
    <h1>Found #StructCount(duplicates)# duplicates, took ~#time# s</h1>
    
    <cfloop collection="#duplicates#" item="checksum">
    <p>
        <!--- display all found paths of duplicate --->
        <cfloop array="#duplicates[checksum]#" index="path">
            #HTMLEditFormat(path)#<br/>
        </cfloop>
        <!--- render only last duplicate, they are the same image any way --->
        <cfimage action="writeToBrowser" source="#path#" />
    </p>
    </cfloop>
    
    </cfoutput>