::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: 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 阅读(1162)
评论(0) 编辑 收藏 所属分类:
DOS Windows