Board logo

标题: 求解文件树智能同步批处理程序 [打印本页]

作者: qzwqzw    时间: 2010-1-7 15:57     标题: 求解文件树智能同步批处理程序

已有两个文件树,他们有很多相同文件(夹),但有些不同名或同路径,也有一些对方所没有的文件(夹),要求在最少的时间内使这两个文件夹最大可能的同步。最少的时间主要是指尽可能少的IO操作,最大的同步主要是指文件树结构完全相同,在此基础上保证最大的数据完整和最小的数据冗余,同时尽可能保持符合文件树原有的树结构。

同步原则:
1、判断文件相同的唯一依据就是文件内容或者其相关值(比如其MD5或CRC校验值),文件名、文件路径、创建及修改时间、标签及元属性仅在判断为相同文件后确认如何操作的参考;

2、两个相同文件处于不同的相对位置或不同名均视作不同路径,以修改时间为准,旧文件树做移动改名操作,并在原处留有硬链接;新文件树仅在对应位置做硬链接;一个文件如果对应多个相同文件,则只处理路径上最接近的相同文件;

3、对相同路径(同名同文件夹)的不同文件,以修改时间为准,新文件继续保留原文件名,旧文件增加_old_的前缀,然后互相复制到对方相应路径下;


4、对同时存在同名不同路径与不同名同路径两种情况的文件,不论同步前出现,还是同步时出现,均先按相同文件处理,再按同路径文件处理;

5、分别独有的文件互相复制到对方对应路径下,如果此地其它文件均在同步中移动到另一处,则此文件也响应移动另一处,并在原处留有硬链接,操作后两文件树结构完全一致;


6、其它情况下不做任何处理,比如某个文件树自身存在相同的文件;

7、程序可以只生成同步方案,也就是文件具体操作的批处理程序,以便用户确认是否操作;


8、对复制、移动、改名和创建硬链接操作,可以允许用户介入选择如何复制、移动、改名或创建硬链接,也可以允许用户选择不复制、移动、改名或创建硬链接。

[ 本帖最后由 qzwqzw 于 2010-1-7 16:40 编辑 ]
作者: 随风    时间: 2010-1-7 23:13

qzwqzw兄的题真是有难度啊,光理解题意就把我绕晕了~
有几处不明白

首先什么是硬链接?

1、判断文件相同的唯一依据就是文件内容或者其相关值(比如其MD5或CRC校验值)
如何获取md5值,岂不是要动用第三方软件,如果全是txt文件还可以fc比较一下,
非文本文件能否fc没试过,不知道可不可以

2、两个相同文件处于不同的相对位置或不同名均视作不同路径
如果会出现这种情况,那么也就是说要把每个文件都逐一作对比了,那样将会n多个组合啊
批处理不可能有效率吧?

一个文件如果对应多个相同文件,则只处理路径上最接近的相同文件
不理解什么意思,只处理路径上最接近的相同文件,那么剩下的呢?不理它吗?
作者: qzwqzw    时间: 2010-1-8 08:09

硬链接是NTFS的一个特性
可以用fsutil hardlink create <新文件名> <现有文件名> 创建
也可以使用其它第三方工具创建
具体内容可以上百度或Google一下

文件内容、MD5或CRC值的获取采取开放自由的原则
不限制使用第三方软件
只要保证效率和稳定即可

建议先生成文件路径、时间和内容相关值的列表
在把列表先按内容或其相关值排序的话,就不需要逐一对比了

是的,对于多个相同文件中路径不是最接近的相同文件是不处理
对于一些复杂冲突的处理,就会考验程序的智能程度
不过你可以设置成由用户选择是否该处理及如何处理

在完成一楼要求的基础上
可以考虑加入对回收站删除文件列表的读取与处理

也就是说如果发现回收站中存在文件树中的文件
则在另一个文件树也对应做删除处理

首先考虑程序模块的完整,足以实现所有的功能
其次考虑是否够健壮,足以应付各种复杂的冲突情况
再次考虑是否够效率,对于K级文件数的处理不会让人难以忍受
最后考虑是否够清晰,不会让自己也被复杂混乱的代码绕进去

[ 本帖最后由 qzwqzw 于 2010-1-8 08:25 编辑 ]
作者: 523066680    时间: 2010-1-8 08:39

听说公文包可以同步#$@#%!@%……
作者: batman    时间: 2010-1-8 08:43

感觉此主题太有挑战性了,故移动到挑战区,还请qzw兄见谅。

看到qzw这个问题,第一感觉就是批恐怕不能胜任。。。
作者: zqz0012005    时间: 2010-1-8 12:34

感觉本来问题不是很复杂,但被楼主的描述看晕了。
我想可能就是双向同步问题而已,加上备份和创建硬链接。
而且既然是双向同步,硬链接就根本没必要,因为每运行一次bat,同步就完成了,没必要让硬链接实现同步(创建硬链接是这个目的吧,而硬链接不能跨分区,且硬链接所占空间与原文件大小相同,不能节省空间)

另不明白“比如某个文件树自身存在相同的文件”是什么意思,同一目录不可能存在同名文件吧,那你的意思是内容相同?那么就要对一个目录下的所有文件之间都比较其内容才能得出哪些相同?内容相同的文件是否需要都同步到另一个目录?还是只要一个就行了?
作者: qzwqzw    时间: 2010-1-8 19:40

看来楼上的确有些晕了

这个问题是类似于双向同步的问题
仅仅多了文件改名和移动的判定而已
但正因如此才让大家觉得很复杂

备份和硬链接在这里是一回事
都是为了保证两个文件树的完整
不过有一点你错了
正是为了节约空间和IO操作才使用硬链接
看来你需要补充一下这方面的知识了

相同文件我说过了就是指且仅指文件内容相同
与文件名与路径无关
所以同一目录可能存在相同文件
文件树因为包含子目录所以可能存在同名文件

至于多个相同文件的同步处理
我想我已经说的够清楚了
只按处理路径最接近的那一对
剩下的文件如果成了孤立文件
那就按照普通的同步程序互相复制就可以了
作者: anoki    时间: 2010-2-9 00:05

看了楼主说的内容,觉得好晕!呵呵好有挑战性哦!
作者: caruko    时间: 2010-3-23 17:59

下班了,仅想了下流程,提供部分关键代码。下次再上完整的。A1-C1为文本文件.

A1 完全相同,A2新旧不同,A3路径不同但文件相同,B1 疑似相同文件,C1完全不同文件, EOF 指推出判断,也可以输出C1


1 for /r A目录文件,IF EXIST 检查B目录文件,|-有相对位置同名文件存在,则FC对比 |-相同就输出到文本A1(完全相同)
                                            |                                                                                                       |-不同则输出到文本A2(新旧版本)
                                            |_无同名文件 |- 检查目录树   |- 有名字相同 |- size相等,FC,输出A3(路径不同文件相同),否者完全不同,eof
                                                                          |             |- size差距大 eof
                                                                          |             |- size差10%以内,输出B1文本(可能为新旧版本,提交用户选择)
                                                                          |- 无名字相同,但有SIZE相等的,则FC |- 相同则输出A3文本(路径不同)
                                                                                                              |- 不同则eof

2 处理B1列表,让用户选择那些是相同文件,那些是不同文件,分储到A3跟C1。
  处理 A2 列表,旧的更名OLD_ ;
  处理A3列表。

3 A->B 拷贝,忽略存在目标, B->A 拷贝,忽略存在文件。


1, 取得FC结果, FC FILE1 FILE2 && echo 两个文件完全相同
2, 查找SIZE相等的文件,for /r ........do dir /s /-c /b /a:-d |find "%~zi" && echo 找到SIZE相同的文件
3, 检查SIZE差距很小的,我尝试用正则 findstr "%var:~0,-2[0-9][0-9]" ,但是不准确
4, 处理列表,复制,XCOPY可以做大部分,另一部分需要IF EXIST来判断
作者: caruko    时间: 2010-3-24 13:45

做了部分代码,也只测试了前面部分,原来有考虑空格“”问题,但发现问题太多了,索性放弃,目录及文件名最好还是不要出现空格...
  1. @echo off
  2. SETLOCAL ENABLEEXTENSIONS
  3. SETLOCAL ENABLEDELAYEDEXPANSION
  4. set "a_dir=d:\test\a\"
  5. set "b_dir=d:\test\b\"
  6. for /r %a_dir% %%a in (*.h) do call :exist %%a
  7. pause
  8. goto :eof
  9. ;检测同位置文件
  10. :exist
  11. set xd_dir=%*
  12. set xd_dir=!xd_dir:%a_dir%=!
  13. if exist %b_dir%!xd_dir! (
  14.       echo %a_dir%!xd_dir!#%b_dir%!xd_dir! >A1.txt
  15.       ) else (
  16.       call :find %*
  17.    )
  18. goto :eof
  19. ;查找其他目录文件
  20. :find
  21. set fn=%~nx1
  22. dir %b_dir% /s /b !fn! |findstr /v "%1" >temp.txt
  23. if %ERRORLEVEL% EQU 0 (
  24.       ;有不同路径的同名文件
  25.       for /f %%b in (temp.txt) do call :cksize %* %%b
  26.       )else(
  27.       call :findsx
  28.     )
  29. goto :eof
  30. ;对比SIZE大小   
  31. :cksize
  32. if %~z1 EQU %~z2 (
  33.       call :fc %1 %2
  34.       )else
  35.       call :cksx %1 %2
  36.     )
  37. goto :eof
  38. :fc
  39. ;如果目录里大多是网站程序这种文本文件,修改FC参数,可达到较高识别率。
  40. fc %1 %2
  41. if %ERRORLEVEL% EQU 0 (
  42.       ;相同
  43.       echo %1#%2 >A3.txt
  44.       )else(
  45.      ;名字相同,路径不同,SIZE同,FC不同,稍后对比版本时间
  46.      )
  47. goto :eof
  48. :cksx
  49. ;对比属性,主要对比时间,作者,版本,公司等。
  50. goto :eof
  51. :findsx
  52. ;这里搜不到同名文件,的后续步骤,寻找属性接近的文件
  53. ;第一步是搜索SIZE相等的文件。
  54. ;然后搜索其它属性。
  55. ;但属性多的话,需要一段程序将文件属性対映到
复制代码

[ 本帖最后由 caruko 于 2010-3-24 13:46 编辑 ]
作者: caruko    时间: 2010-3-24 16:30

=.= 这是一个测试过的版本,目前只有2个功能,列出“完全相同”“以及同名但不同路径的文件”
  1. ;@echo off
  2. SETLOCAL ENABLEEXTENSIONS
  3. SETLOCAL ENABLEDELAYEDEXPANSION
  4. set "a_dir=d:\test\a\"
  5. set "b_dir=d:\test\b\"
  6. echo 这里保存“同名不同路径”的文件列表 >d:\A3.txt
  7. echo 这里保存“疑似同一功能文件”的文件列表 >d:\B1.txt
  8. echo 这里保存“完全相同”的文件列表 >d:\A1.txt
  9. pushd %b_dir%
  10. for /r %a_dir% %%a in (*.*) do call :exist %%a
  11. pause
  12. goto :eof
  13. ;检测同位置文件
  14. :exist
  15. set xd_dir=%*
  16. set xd_dir=!xd_dir:%a_dir%=!
  17. if exist %b_dir%!xd_dir! (
  18.       echo %* # %b_dir%!xd_dir! >>d:\A1.txt
  19.       ;同位置同名文件,放弃检测,也可调用FC对比,或者对比日期
  20.       ) else (
  21.       call :find %*
  22.    )
  23. goto :eof
  24. ;查找其他目录文件
  25. :find
  26. set fn=%~nx1
  27. dir /a:-d /s /b !fn! |findstr /v "%1" >d:\temp.txt
  28. if %ERRORLEVEL% EQU 0 (
  29.       for /f "tokens=1*" %%b in (d:\temp.txt) do call :cksize %1 %%b
  30.       goto :eof
  31.       )
  32. ;这里是无同名文件的代码
  33. goto :eof
  34. ;对比SIZE大小   
  35. :cksize
  36. if %~z1 equ %~z2 (
  37.       call :fc %1 %2
  38.       goto :eof
  39.       )
  40. call :cksx %1 %2
  41. goto :eof
  42. ;如果目录里大多是网站程序这种文本文件,修改FC参数,可达到较高识别率。
  43. :fc
  44. fc %1 %2
  45. echo fc %~nx1 %~nx2 >>r.txt
  46. if %ERRORLEVEL% EQU 0 (
  47.       echo %1 # %2 >>d:\A3.txt
  48.       goto :eof
  49.       )
  50. ;名字相同,路径不同,SIZE同,FC不同,稍后对比版本时间,或者第三方取得摘要信息
  51. goto :eof
  52. :cksx
  53. ;对比属性,主要对比时间,作者,版本,公司等。
  54. goto :eof
  55. :findsx
  56. ;这里搜不到同名文件,的后续步骤,寻找属性接近的文件
  57. ;第一步是搜索SIZE相等的文件。
  58. ;然后搜索其它属性。
  59. ;但属性多的话,需要一段程序将文件属性対映到
  60. goto :eof
复制代码

作者: CrLf    时间: 2013-3-4 17:46

刚好硬盘满了,我的实现方式是 90%(专业软件查重并手动导出清单)+10%(批处理删除与硬链接)
用到的软件是FindDupFile
添加要处理的盘符或文件夹,取消勾选“检查空文件”项,待检查完后导出为 a.txt,再用这个批来进行后续处理:
  1. @echo off
  2. for /f "delims=U" %%a in ('cmd /u /c echo 唉') do set "tab=%%a"
  3. (for /f "tokens=1* delims=%tab%" %%a in ('type a.txt') do (
  4. set "files=%%b"
  5. setlocal enabledelayedexpansion
  6. for %%c in ("!files:%tab%=" "!") do (
  7. endlocal
  8. del /f "%%~c">nul&&mklink /h "%%~c" "%%~a"
  9. )
  10. ))
  11. pause
复制代码

作者: CrLf    时间: 2013-3-4 17:53

不过搜了下发现好像有更方便的玩意,还是开源的:
finddupe
见此贴:
http://bbs.bathome.net/redirect. ... 5&fromuid=30406
下载后执行下面的命令就可以跷二郎腿了,唯一不爽的是似乎要 c++ 库支持,不太通用呀
  1. finddupe -hardlink d:\
复制代码





欢迎光临 批处理之家 (http://bathome.net./) Powered by Discuz! 7.2