[新手上路]批处理新手入门导读[视频教程]批处理基础视频教程[视频教程]VBS基础视频教程[批处理精品]批处理版照片整理器
[批处理精品]纯批处理备份&还原驱动[批处理精品]CMD命令50条不能说的秘密[在线下载]第三方命令行工具[在线帮助]VBScript / JScript 在线参考
返回列表 发帖

[文件操作] [已用解压参数设置方式解决]求批处理移动文件代码优化或更简单其它有效方法

本帖最后由 hfxiang 于 2022-8-15 07:57 编辑

需要:每隔一段时间会收到一百多个压缩数据包,每个包当中有不确定个数的文件,解压后还存在子文件夹,之前无重名文件,就用以下简单指令(直接在cmd命令行下执行)即可把文件从子文件夹移动到当前文件夹,
  1. for /r %a in (*) do move /y "%a" .
复制代码
之后删除所有子文件夹即可。

但随着文件数量增加,出现许多重名文件,以上指令将会用新文件覆盖原有的同名文件,故写了以下脚本(详见“3.移动文件到当前文件夹代码”)来解决,但总觉得其执行效率实在太低(不作信息回显提升亦不明显),希望有大神能给予优化,或指引一下更简单其它有效方法,不胜感激。

创建测试文件需用到第3方工具seq.exe,下载地址:http://bcn.bathome.net/tool/seq.exe

1.创建100个文件夹(直接在cmd命令行下执行)
  1. (for /f "usebackq tokens=*" %a in (`seq -f "%cd%\Folder%03g" 1 100 2^>nul`) do @mkdir "%a")>nul 2>&1
复制代码
2.在每个子文件夹下创建10个(空)文件(test001.dat~test010.dat)(直接在cmd命令行下执行)
  1. (for /d %a in ("%cd%\*") do @for /f "usebackq tokens=*" %b in (`seq -f "%a\test%03g.dat" 1 10 2^>nul`) do @echo;2>%b)>nul 2>&1
复制代码
3.移动文件到当前文件夹代码(也就是希望优化或另劈方法的地方)
  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set /a fn0=0
  4. set /a fn1=0
  5. set /a fn2=0
  6. set /a fn3=0
  7. set "Folder=%~dp0"
  8. set "Dir_a=%~a1"
  9. if defined Dir_a if "[%Dir_a:~0,1%]"=="[d]" (
  10. set "Folder=%~f1"
  11. ) else (
  12. set "Folder=%~dp1"
  13. )
  14. if /i "[%Folder:~-1,1%]"=="[\]" if /i not "[%Folder:~-2,1%]"=="[:]" set "Folder=%Folder:~0,-1%"
  15. cd /d "%Folder%"
  16. for /f "delims==" %%a in ('set exist_File_ 2^>nul') do set "%%a="
  17. for /f %%a in ('dir /b/a-d') do set "exist_File_%%a=True"
  18. for /f %%a in ('dir /b/a-d/s') do if /i not [%%~dpa]==[%cd%\] (
  19. set "Check=True"
  20. if not defined exist_File_%%~nxa (
  21. set "exist_File_%%~nxa=True"
  22. set new_FileName=%cd%\%%~nxa
  23. ) else (
  24. call :No_DupFile "%%~na" "%%~xa" newFileName Check
  25. if /i [!Check!]==[True] set "exist_File_!newFileName!=True"
  26. set new_FileName=%cd%\!newFileName!
  27. )
  28. set /a fn0+=1
  29. echo;!fn0! "%%a" --^> "!new_FileName!"
  30. if /i [!Check!]==[True] (
  31. (
  32. move /y "%%a" "!new_FileName!">nul 2>&1
  33. ) && (
  34. set /a fn1+=1
  35. echo; 移动成功
  36. ) || (
  37. set /a fn2+=1
  38. echo; 移动失败
  39. )
  40. ) else (
  41. set /a fn3+=1
  42. echo; 改名失败
  43. )
  44. )
  45. echo;
  46. if %fn0% GTR 0 echo;待移动文件: %fn0% 个
  47. if %fn1% GTR 0 echo;移动成功: %fn1% 个文件
  48. if %fn2% GTR 0 echo;移动失败:%fn2% 个文件
  49. if %fn3% GTR 0 echo;改名失败:%fn3% 个文件
  50. endlocal
  51. echo;&pause
  52. exit /b
  53. :No_DupFile <oldFileName> <extName> [newFileName] [Check_ID]
  54. setlocal enableDelayedExpansion
  55. set "Check=False"
  56. for /l %%b in (1,1,999) do (
  57. set n=00%%b
  58. set n=!n:~-3!
  59. if not defined exist_File_%~1__!n!%~2 (
  60. set "FileName=%~1__!n!%~2"
  61. set "Check=True"
  62. goto :end_Loop
  63. )
  64. )
  65. :end_Loop
  66. endlocal&set "%3=%FileName%"&set "%4=%Check%"&goto :EOF
复制代码

几经寻找,从DOS Batch - Function Tutorial( https://www.dostips.com/DtTutoFu ... .RecursiveFunctions )中得到启示,使用递归方式处理,子过程避免使用 setlocal enableDelayedExpansion 启用 "延迟环境变量扩展" ,运行性能出现明显提升,请大神们指导。改进后代码如下:
  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set /a fn0=0
  4. set /a fn1=0
  5. set /a fn2=0
  6. set /a fn3=0
  7. set "Folder=%~dp0"
  8. set "Dir_a=%~a1"
  9. if defined Dir_a if "[%Dir_a:~0,1%]"=="[d]" (
  10. set "Folder=%~f1"
  11. ) else (
  12. set "Folder=%~dp1"
  13. )
  14. if /i "[%Folder:~-1,1%]"=="[\]" if /i not "[%Folder:~-2,1%]"=="[:]" set "Folder=%Folder:~0,-1%"
  15. cd /d "%Folder%"
  16. for /f "delims==" %%a in ('set exist_File_ 2^>nul') do set "%%a="
  17. for /f %%a in ('dir /b/a-d') do set "exist_File_%%a=True"
  18. for /f %%a in ('dir /b/a-d/s') do if /i not [%%~dpa]==[%cd%\] (
  19. set "Check=True"
  20. if not defined exist_File_%%~nxa (
  21. set "exist_File_%%~nxa=True"
  22. set new_FileName=%cd%\%%~nxa
  23. ) else (
  24. set /a P_Serial=0
  25. call :No_DupFile "%%~na","%%~xa",P_Serial,Serial
  26. set "exist_File_%%~na__!Serial!%%~xa=True"
  27. if !P_Serial! GTR 999 set "Check=False"
  28. set new_FileName=%cd%\%%~na__!Serial!%%~xa
  29. )
  30. set /a fn0+=1
  31. echo;!fn0! "%%a" --^> "!new_FileName!"
  32. if /i [!Check!]==[True] (
  33. (
  34. move /y "%%a" "!new_FileName!">nul 2>&1
  35. ) && (
  36. set /a fn1+=1
  37. echo; 移动成功
  38. ) || (
  39. set /a fn2+=1
  40. echo; 移动失败
  41. )
  42. ) else (
  43. set /a fn3+=1
  44. echo; 改名失败
  45. )
  46. )
  47. echo;
  48. if %fn0% GTR 0 echo;发现文件: %fn0% 个
  49. if %fn1% GTR 0 echo;移动成功: %fn1% 个文件
  50. if %fn2% GTR 0 echo;移动失败:%fn2% 个文件
  51. if %fn3% GTR 0 echo;改名失败:%fn3% 个文件
  52. endlocal
  53. echo;&pause
  54. exit /b
  55. :No_DupFile <FileName>,<extName>,[P_Serial],[Serial]
  56. setlocal
  57. set /a P_Serial=1+%~3
  58. set Serial=00%P_Serial%
  59. set Serial=%Serial:~-3%
  60. if %P_Serial% LEQ 999 if defined exist_File_%~1__%Serial%%~2 call :No_DupFile "%~1","%~2",P_Serial,Serial
  61. (endlocal
  62. SET "%3=%P_Serial%"
  63. SET "%4=%Serial%"
  64. )
  65. goto :EOF
复制代码

TOP

解压命令里不是有自动重命名和所有文件放到一个目录的参数吗
1

评分人数

TOP

本帖最后由 hfxiang 于 2022-8-15 07:37 编辑

回复 3# idwma


    这样重名文件能自动改名吗?如果这样就可用压缩再解压的方式解决问题。俺要试一下。谢谢

TOP

回复 4# hfxiang
刚才的代码有问题,重发一下。根据一位大佬的代码修改而成,未经测试:
  1. @echo off
  2. for /d %%a in (*) do (
  3.     pushd "%%a"
  4.     for /f "delims=" %%i in ('dir /s /b /a-d') do (
  5.         set "filename=%%~ni"
  6.         setlocal enabledelayedexpansion
  7.         if not exist "%~dp0!filename!%%~xi" (
  8.             copy "%%i" "%~dp0"
  9.         ) else (
  10.             set "n=1"
  11.             call :Next "%%~xi"
  12.             copy "%%i" "%~dp0!filename!(!n!)%%~xi"
  13.         )
  14.         endlocal
  15.     )
  16.     popd
  17. )
  18. pause & exit
  19. :Next
  20. if exist "%~dp0!filename!(!n!)%~1" (
  21.     set /a n+=1
  22.     goto :Next
  23. )
复制代码

TOP

回复 5# qixiaobin0715


感谢回复。谢谢。
但[if exist "%~dp0!filename!(!n!)%~1"]代码俺不太敢用,之前经无数次测试,其在文件量大时,效率实在无法接受。

TOP

我觉得使用call跳出循环体可能在效率上会有一些损失,但你在1、2楼的代码中for循环的in中使用了'set'命令,循环体中多处使用了组合命令||和&&才是效率低下的主要原因。

TOP

回复 7# qixiaobin0715


你说得很对,这些指令会有效率损失,但[if  exist ]要访问磁盘,这个访问多了,其效率损失会让人无法接受

TOP

本帖最后由 qixiaobin0715 于 2022-8-15 13:32 编辑

回复 8# hfxiang
搜索文件没你想象的那么慢。
单独测试了一下此语句,十万个文件瞬间完成。

TOP

回复 9# qixiaobin0715


哪是你的硬盘IO非常强大,俺的硬盘读写是明显感觉到一跳一跳的 ,时时让俺心惊肉跳的

TOP

回复 10# hfxiang
应当是在for循环中使用call命令的原因。见帖子:
http://bbs.bathome.net/viewthread.php?tid=4831&from=favorites
中的:
第一大条中第1小条的描述。

TOP

返回列表