posts - 41,  comments - 40,  trackbacks - 0

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Author: NeedJava
::
:: Modified: 2007-07-07
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@ECHO OFF

SETLOCAL EnableDelayedExpansion

ECHO 搜索重复的图片,按任意键继续。

PAUSE>NUL


DEL /F /Q list.txt 2>NUL

DEL /F /Q sorted.txt 2>NUL

DEL /F /Q clone.txt 2>NUL


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 生成“文件大小|文件路径”,再排序,内容诸如:
::
:: 25329|C:\Documents and Settings\Administrator\桌面\02.jpg
::
:: 我把文件大小加上100000000,即100MB,这样方便SORT命令比较大小,那么内容变成如下:
::
:: 100025329|C:\Documents and Settings\Administrator\桌面\02.jpg
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
FOR /R %%a IN ( *.jpg ) DO SET /A size=%%~za+100000000 & ECHO !size!^|%%a>>list.txt


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 根据列表每行前面所列出的文件大小进行排序
::
:: 我把文件大小加上100000000,即100MB,这样方便SORT命令比较大小
::
:: 否则SORT会给我“1、123、1235、2、21、3”这样的顺序
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SORT /R list.txt /O sorted.txt 2>NUL


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 我不认为需要对5MB以上的图片文件进行二进制比较,它们够显眼的了
::
:: 只有大小一样才需要作进一步的二进制比较,否则就是搞笑了
::
::
:: FC搞笑:名称字数超过185个的文件夹不予理会
::
:: DIR搞笑:会把路径中的一些Unicode码(如30FB)用半角问号“?”代替,记事本也如此
::
:: FOR /R搞笑:不但会把Unicode码(如30FB)用半角问号“?”代替,还会把路径中的“!”、“^”删除
::
:: 以上这些微软的搞笑BUG,使得我的这个批处理也跟着有了BUG:路径中不能有“!”、“^”和一些Unicode码
::
::
:: FC命令返回代码含义:
::
:: 0   完全相同
::
:: 1   不完全同
::
:: 2   缺少文件
::
::
:: FIND命令返回代码含义:
::
:: 0   找到字符串
::
:: 1   没有找到字符串
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SET preSize=

SET preFile=

FOR /F "tokens=1,2 delims=|" %%a IN ( sorted.txt ) DO (

    SET /A curSize=%%a-100000000

    SET curFile=%%b

    ECHO ========================================================================
    ECHO.
    ECHO 上个文件大小:!preSize!
    ECHO.
    ECHO 当前文件大小:!curSize!
    ECHO.
    ECHO 上个文件路径:!preFile!
    ECHO.
    ECHO 当前文件路径:!curFile!
    ECHO.

    IF NOT "!preFile!"=="" IF !preSize! LEQ 5000000 (

       IF !preSize! EQU !curSize! (

          FC.EXE /B "!preFile!" "!curFile!">NUL

          IF !ERRORLEVEL! EQU 0 (

             ECHO 两个文件完全相同!
             ECHO.

             IF /I NOT "!always!"=="true" (

                ECHO.>>clone.txt

                ECHO !preSize!字节>>clone.txt

                ECHO !preFile!>>clone.txt

                SET always=true

             )

             ECHO !curFile!>>clone.txt

          )

       ) ELSE (

         SET always=false

       )

    )

    SET /A preSize=!curSize!

    SET preFile=!curFile!

)


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 删除用过的文件等结尾工作
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
DEL /F /Q list.txt 2>NUL

DEL /F /Q sorted.txt 2>NUL

@ECHO ON

最近要在Win2000下工作,发现Win2000(没打SP4)提供的FC.EXE命令有问题,不论是在Shell下还是在批处理,一些大小一样的图片,比较的结果都是让%ERRORLEVEL%为0,也就是相同,大家有兴趣可以试试下面两个文件,注意,把jpg改成gif的。





由于上述比较只是假设同种文件的复本,没有考虑同样大小文件的干扰,按习惯,应该一一比较,如〔1、2、3、4〕,需要比较〔1、2〕、〔1、3〕、〔1、4〕、〔2、3〕、〔2、4〕、〔3、4〕这几组,如下:

假设相同文件有n个,理想FOR命令如下:

for( int i=1; i<n; i++ )
   {
     for( int j=i+1; j<=n; j++ )
        {
          compare i and j...
        )
   }

但是FOR命令的局限,很难做到,所以自己也在考虑更好的办法,如下是第二次改进:

::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: Name: 搜索重复图片(或其他任意类型、大小的文件,对0字节的也比较)
::
:: Author: NeedJava
::
:: Modified: 2007-07-30
::
:: 注意:你可以在任何地方使用此批处理,但必须保持文件作者及注释部分的完整
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
@ECHO OFF

SETLOCAL EnableDelayedExpansion

ECHO 搜索重复的图片,按任意键继续。
ECHO.

PAUSE>NUL

DEL /F /Q hash.txt 2>NUL
DEL /F /Q sort.txt 2>NUL
DEL /F /Q clone.txt 2>NUL
DEL /F /Q lost.txt 2>NUL

RD /S /Q "Clone\" 2>NUL & MD "Clone\" 2>NUL


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 生成“文件大小|文件路径”,再排序,内容诸如:
::
:: 25329|C:\Documents and Settings\Administrator\桌面\02.jpg
::
:: 把文件大小加上100000000,即100MB,这样方便SORT命令比较大小,那么内容变成如下:
::
:: 100025329|C:\Documents and Settings\Administrator\桌面\02.jpg
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CLS

ECHO 正在搜索文件,请稍候……
ECHO.

FOR /R %%a IN ( *.jpg ) DO (

    SET /A size=%%~za+100000000

    ECHO !size!^|%%a>>hash.txt

)


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 根据列表每行前面所列出的文件大小进行排序
::
:: 把文件大小加上100000000,即100MB,这样方便SORT命令比较大小
::
:: 否则SORT会给我们“1、123、1235、2、21、3”这样的顺序
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CLS

ECHO 正在排序文件,请稍候……
ECHO.

IF EXIST hash.txt (

   SORT /R hash.txt /O sort.txt 2>NUL

)


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 把大小相同的文件分离成一个个单独的文件,方便后面的相互比较
::
:: 我不认为需要对5MB以上的图片文件进行二进制比较,它们够显眼的了
::
:: 只有大小一样才需要作进一步的二进制比较,否则就是搞笑了
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
CLS

ECHO 正在分离文件,请稍候……
ECHO.

IF EXIST sort.txt (

   SET "preSize="

   SET "preFile="

   FOR /F "tokens=1,2 delims=|" %%a IN ( sort.txt ) DO (

       SET /A curSize=%%a-100000000

       SET "curFile=%%b"

       IF NOT "!preFile!"=="" IF !preSize! LEQ 5000000 (

          IF !preSize! EQU !curSize! (

             IF /I NOT "!always!"=="true" (

                ECHO !preSize!^|!preFile!>"Clone\!preSize!.vab"

                SET "always=true"

             )

             ECHO !curSize!^|!curFile!>>"Clone\!preSize!.vab"

          ) ELSE (

            SET "always=false"

          )

       )

       SET /A preSize=!curSize!

       SET "preFile=!curFile!"

   )

)


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 微软一些DOS命令的搞笑BUG:
::
:: FC:名称的字数超过185个的文件夹不予理会
::
:: DIR:把路径中的一些Unicode码(如30FB)用半角问号“?”代替,记事本也如此
::
:: FOR /R:不但把Unicode码(如30FB)用半角问号“?”代替,还会删除路径中的“!”和“^”
::
:: 以上这些微软BUG,使这个批处理也有了BUG:路径中不能有“!”、“^”和一些Unicode码
::
::
:: FC命令返回代码含义:
::
:: 0   完全相同
::
:: 1   不完全同
::
:: 2   缺少文件
::
::
:: FIND命令返回代码含义:
::
:: 0   找到字符串
::
:: 1   没有找到字符串
::
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:reload

IF EXIST "Clone\" (

   FOR /R "Clone\" %%a IN ( *.vab ) DO (

       SET "list=Clone\%%~nxa"

       SET /A num=1

       GOTO cycle

   )

)

GOTO delete


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 原理:
::
:: 假设有DATA[A B C D B A A]这个7位数组需要自身比较,按照正常的方法,如下:
::
:: for( int i=0; i<n-1; i++ )
::    {
::      for( int j=i+1; j<n; j++ )
::         {
::           compare DATA[i] DATA[j]...
::         }
::    }
::
:: 需要比较N*(N-1)/2次,即7*(7-1)/2=21次,如下:
::
:: [A B]、[A C]、[A D]、[A B]、[A A]、[A A]
::
:: [B C]、[B D]、[B B]、[B A]、[B A]
::
:: [C D]、[C B]、[C A]、[C A]
::
:: [D B]、[D A]、[D A]
::
:: [B A]、[B A]
::
:: [A A]
::
:: 但是从上面的列表可以发现,有些已经被确定和某个数相同的数,如[A]和[B]两类,
::
:: 在后面依然和别的数继续比较,这是不科学的,应该在找到相同类后,删除它们。
::
:: 也就是说,一旦找到相同的类,就把它们剔除出循环,那么循环应该如下:
::
:: A B C D B A A
::
:: 第一次循环找出所有相同的[A]后,待比较列表动态变为:
::
:: B C D B
::
:: 第二次循环找出所有相同的[B]后,待比较列表动态变为:
::
:: C D
::
:: 如上,那么比较为:
::
:: [A B]、[A C]、[A D]、[A B]、[A A]、[A A]
::
:: [B C]、[B D]、[B B]、[BXA]、[BXA]
::
:: [C D]、[CXB]、[CXA]、[CXA]
::
:: [DXB]、[DXA]、[DXA]
::
:: [BXA]、[BXA]
::
:: [AXA]
::
:: 中间有X的表示已被缩减的,即最终比较为:
::
:: [A B]、[A C]、[A D]、[A B]、[A A]、[A A]
::
:: [B C]、[B D]、[B B]
::
:: [C D]
::
:: 整个批处理原理:
::
:: 1、FOR命令通过%%~za生成零散的,每列开头为文件大小的文件列表hash.txt,如:
::
::    100017000|E:\123.jpg
::    100017000|E:\345.jpg
::    100056732|E:\ffff.jpg
::    100017000|E:\OK\123.jpg
::    100056732|E:\OK\ffff.jpg
::    100012345|E:\OK\gag.jpg
::
:: 2、SORT命令将hash.txt从大到小(当然也可以从小到大)排序成sort.txt,如:
::
::    100056732|E:\ffff.jpg
::    100056732|E:\OK\ffff.jpg
::    100017000|E:\123.jpg
::    100017000|E:\345.jpg
::    100017000|E:\OK\123.jpg
::    100012345|E:\OK\gag.jpg
::
:: 3、分析sort.txt列表文件,如果有两行以上大小相同的纪录,分离到同一个新列表文件:
::
::    文件名:Clone\56732.vab,内容如下:
::    100056732|E:\ffff.jpg
::    100056732|E:\OK\ffff.jpg
::
::    文件名:Clone\17000.vab,内容如下:
::    100017000|E:\123.jpg
::    100017000|E:\345.jpg
::    100017000|E:\OK\123.jpg
::
:: 4、通过双层嵌套FOR命令,进行比较,相同的纪录进clone.txt,也就是最终文件;
::
::    不相同的则纪录进新的文件comparedN.vab,此处N为数字1、2、3、4,如果不删除,
::
::    可以看到动态的待比较列表,用于调试。
::
::    一旦生成了comparedN.vab文件,就表示有未比较的文件,则将待比较列表list设成
::
::    最新的comparedN.vab文件,并且跳转到双层嵌套FOR命令开头cycle,重新循环。
::
::    一旦待比较列表list消失,则表明此类大小的文件比较完毕,跳转到reload,分析下
::
::    一个大小的文件列表。
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:cycle

REM TYPE !list! & PAUSE

IF EXIST !list! (

   FOR /F "tokens=1,2 delims=|" %%M IN ( !list! ) DO (

       SET "found=false"

REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM    ::
REM    :: 我们分析的文件内容是用“|”分隔的,如下:
REM    ::
REM    :: 56732|E:\ffff.jpg
REM    ::
REM    :: tokens=1,2 delims=|会把内容分割成两部分,即56732和E:\ffff.jpg
REM    ::
REM    :: 第一个部分用变量%%m表示,也就是文件大小56732
REM    ::
REM    :: 第二个部分用变量%%n表示,也就是文件完整的路径E:\ffff.jpg
REM    ::
REM    :: skip=1表示跳过一行,用来防止自身比较。当然为了稳妥,下面还是用了判断
REM    ::
REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
       FOR /F "skip=1 tokens=1,2 delims=|" %%m IN ( !list! ) DO (

REM        :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM        ::
REM        :: 必须是大小相同的文件才能比较。不是必要,但稳妥起见还是判断一下
REM        ::
REM        :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
           IF /I "%%M"=="%%m" (

REM           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM           ::
REM           :: 不能自己跟自己比较。虽然上面用skip=1跳过,但稳妥起见还是判断一下
REM           ::
REM           ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
              IF /I NOT "%%N"=="%%n" (

                 CLS

                 ECHO 正在比较以下%%M字节的两个文件:
                 ECHO %%N
                 ECHO %%n
                 ECHO.

REM              PAUSE

REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM              ::
REM              :: 根据FC命令用二进制比较,所返回的错误码来判断两个文件是否相同
REM              ::
REM              :: Windows 2000下FC命令有问题,所以Windows 2000不能使用此批处理
REM              ::
REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                 FC.EXE /B "%%N" "%%n">NUL 2>NUL

REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM              ::
REM              :: 两个文件比较后完全相同,FC命令会返回0
REM              ::
REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                 IF !ERRORLEVEL! EQU 0 (

                    ECHO 两个文件完全相同!
                    ECHO.

REM                 PAUSE

REM                 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM                 ::
REM                 :: 如果!found!为true,就表示在比较循环中,遇到了第一次相同
REM                 ::
REM                 :: 用于在找到的列表clone.txt中写入新的标题
REM                 ::
REM                 ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                    IF /I NOT "!found!"=="true" (

                       ECHO [%%M Bytes]>>clone.txt
                       ECHO %%N>>clone.txt

                       SET "found=true"

                    )

                    ECHO %%n>>clone.txt

                 )

REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM              ::
REM              :: 两个文件比较后不相同,FC命令会返回1
REM              ::
REM              :: 把不相同的文件写入下一个待比较列表
REM              ::
REM              :: 这个列表将取代现有列表用于下次循环
REM              ::
REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                 IF !ERRORLEVEL! EQU 1 (

REM                 ECHO %%n & ECHO. & PAUSE

                    ECHO %%m^|%%n>>"compared!num!.vab"

                 )

REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM              ::
REM              :: 找不到相应的文件时,FC命令会返回2
REM              ::
REM              :: 由于FOR /R命令得出的路径,会删除路径中的“!”和“^”,
REM              ::
REM              :: 这会导致虽然待比较列表有路径(错误的),然而FC命令却找不到
REM              ::
REM              :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
                 IF !ERRORLEVEL! EQU 2 (

REM                 ECHO %%n & ECHO. & PAUSE

                    IF NOT EXIST "%%N" (

                       ECHO %%M^|%%N>>lost.txt

                    )

                    IF NOT EXIST "%%n" (

                       ECHO %%m^|%%n>>lost.txt

                    )

                 )

              )

           )

       )

REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM    ::
REM    :: 如果!found!为true,就表示在这次循环中找到了相同文件
REM    ::
REM    :: 那么针对这次循环的结束,在找到的列表clone.txt中追加一个空行,用来分隔
REM    ::
REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
       IF /I "!found!"=="true" (

          ECHO.>>clone.txt

       )

REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM    ::
REM    :: 删除现有的待比较列表,必须删除,否则会陷入死循环
REM    ::
REM    :: 这也是跳出循环的判断条件,very important!
REM    ::
REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
       DEL /F /Q "!list!" 2>NUL

REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM    ::
REM    :: 如果刚才的循环,有一些文件不相同,就会存在新的待比较列表
REM    ::
REM    :: 我们把它设为新的待比较列表,准备跳转到循环开头,重新循环
REM    ::
REM    :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
       IF EXIST "compared!num!.vab" (

          SET "list=compared!num!.vab"

          SET /A num+=1

       ) ELSE (

         GOTO reload

       )

       GOTO cycle

   )

)


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 删除用过的文件
::
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:delete

DEL /F /Q hash.txt 2>NUL
DEL /F /Q sort.txt 2>NUL

RD /S /Q "Clone\" 2>NUL

IF EXIST clone.txt %SystemRoot%\NOTEPAD.EXE clone.txt

@ECHO ON

posted on 2007-07-08 21:40 NeedJava 阅读(1026) 评论(0)  编辑  收藏 所属分类: DOS Windows

只有注册用户登录后才能发表评论。


网站导航: