Board logo

标题: [文件操作] 批处理获取子文件夹大小并添加到文件夹名前 [打印本页]

作者: gflrlm    时间: 2014-4-19 14:42     标题: 批处理获取子文件夹大小并添加到文件夹名前

本帖最后由 pcl_test 于 2016-7-27 22:25 编辑

写此代码的初衷: 本人是电影爱好者,有上千部电影在同一个目录movie下。 每部电影都单独存在于一个文件夹内,如 "钢铁侠" "极品飞车" "玩具总动员" 等, 每部电影大小不一,有的几百兆,有的几个G,所以我想在每个文件夹名字的前面加上该部电影的大小,以G为单位取小数点后2位。

如下所示:
f:\01movie\1.21GB---决斗犹马镇\决斗犹马镇.srt
f:\01movie\0.35GB---科学怪人.mkv
f:\01movie\0.98GB---尼古拉斯·凯奇-狂暴飞车\狂暴飞车.mkv
f:\01movie\4.37GB---杰森·斯坦森-暂告安全\暂告安全.mkv
f:\01movie\7.93GB---我们曾是战士\我们曾是战士.mkv

本程序功能:
1,在每个文件夹的前面,添加该文件夹大小,以GB为单位
2,本程序可以正确处理文件路径中存在的任意类型特殊字符,包括感叹号,& ,空格等字符。
3,其实贴目的也是记录一下自己的bat学习历程。对变量嵌套和变量扩展有了更进一步的认识。尤其是对setlocal enabledelayedexpansion 和 setlocal disabledelayedexpansion有了更深入的认识。后者是我第一次在代码里面用上,解决了变量延迟开启后感叹号丢失的问题。
再加一句,里面的除法是调用vbs实现的,用bat做除法比较麻烦,尤其是GB TB这么大的字节数,所以就没有写那段代码。
  1. @echo off
  2. set "dir=./"
  3. set /a KB=1024
  4. set /a MB=1024*1024
  5. set /a GB=1024*1024*1024
  6. set /a TB=1024*1024*1024*1024
  7. rem 注意这里我使用%curr_dir%来代替%cd%的原因是:
  8. rem 当批处理本身位于C: D: E:等根目录下时,%cd% 的结果是 C:\ D:\ E:\ 有个反斜杠在这里,导致del /f /s /q %cd%\dir.txt的时候提示  "文件名、目录名或卷标语法不正确。"
  9. rem 这样导致批处理的兼容性比较差,所以:
  10. rem 使用%0来提取当前批处理的路径,%curr_dir% 就没有这个问题。
  11. echo current dir is %cd%;
  12. for %%i in (%0) do (set curr_dir=%%~dpi)
  13. echo current dir is %curr_dir%;
  14. echo "请选择要计算的目录类型,1是只取第一层目录,2是递归当前目录,默认是第一层目录"
  15. set /p "dir_type="
  16. if NOT DEFINED dir_type echo "dir_type is Null" && dir /a:d /b    "%dir%"  | sort /r> "%curr_dir%directory.txt"  && goto continue_calc
  17. if %dir_type% EQU 1     echo "dir_type is 1"    && dir /a:d /b    "%dir%"  | sort /r> "%curr_dir%directory.txt"
  18. if %dir_type% EQU 2     echo "dir_type is 2"    && dir /a:d /b /s "%dir%"  | sort /r> "%curr_dir%directory.txt"
  19. :continue_calc
  20. del /f /s /q "%curr_dir%calc_1.vbs" >nul 2>nul
  21. del /f /s /q "%curr_dir%dir_size.txt" >nul 2>nul
  22. del /f /s /q "c:\vbs_result.txt" >nul 2>nul
  23. rem 使用vbs脚本创建一个简单的除法计算器。
  24. echo  Dim a1,a2,a3                                            > "%curr_dir%calc_1.vbs"
  25. echo  Dim str1                                                >>"%curr_dir%calc_1.vbs"
  26. echo  Dim a(2)                                                >>"%curr_dir%calc_1.vbs"
  27. echo  Dim i                                                   >>"%curr_dir%calc_1.vbs"
  28. echo  i=0                                                     >>"%curr_dir%calc_1.vbs"
  29. echo  Set oArgs = WScript.Arguments                           >>"%curr_dir%calc_1.vbs"
  30. echo      For Each s In oArgs                                 >>"%curr_dir%calc_1.vbs"
  31. echo          a(i)=s                                          >>"%curr_dir%calc_1.vbs"
  32. echo          i=i+1                                           >>"%curr_dir%calc_1.vbs"
  33. echo          'MsgBox(s)                                      >>"%curr_dir%calc_1.vbs"
  34. echo      Next                                                >>"%curr_dir%calc_1.vbs"
  35. echo  Set oArgs = Nothing                                     >>"%curr_dir%calc_1.vbs"
  36. echo  'MsgBox(a(0))                                           >>"%curr_dir%calc_1.vbs"
  37. echo  'MsgBox(a(1))                                           >>"%curr_dir%calc_1.vbs"
  38. echo  '                                                       >>"%curr_dir%calc_1.vbs"
  39. echo  a1=145555555555555555                                   >>"%curr_dir%calc_1.vbs"
  40. echo  a2=1255555555.23                                        >>"%curr_dir%calc_1.vbs"
  41. echo  a3=a(0)/a(1)                                            >>"%curr_dir%calc_1.vbs"
  42. echo  a3=round(a3,2)                                          >>"%curr_dir%calc_1.vbs"
  43. echo  If a3^<1 Then                                           >>"%curr_dir%calc_1.vbs"
  44. echo     str1 = 0^&a3                                         >>"%curr_dir%calc_1.vbs"
  45. echo     If Len(str1) ^<4 Then str1 = str1^&"0" End if       >>"%curr_dir%calc_1.vbs"
  46. echo  Else                                                    >>"%curr_dir%calc_1.vbs"
  47. echo    If a3^<100 Then                                       >>"%curr_dir%calc_1.vbs"
  48. echo       if Len(a3)^<4 then                                 >>"%curr_dir%calc_1.vbs"
  49. echo         if Len(a3)=1 then str1 = a3^&".00" end if '1     >>"%curr_dir%calc_1.vbs"
  50. echo         if Len(a3)=2 then str1 = a3^&".0" end if  '10    >>"%curr_dir%calc_1.vbs"
  51. echo         if Len(a3)=3 then str1 = a3^&"0" end if   '1.1   >>"%curr_dir%calc_1.vbs"
  52. echo       else                                               >>"%curr_dir%calc_1.vbs"
  53. echo         str1=a3                                   '10.1  >>"%curr_dir%calc_1.vbs"
  54. echo         If Len(str1) ^<4 Then str1 = str1^&"0" End if   >>"%curr_dir%calc_1.vbs"
  55. echo       End If                                             >>"%curr_dir%calc_1.vbs"
  56. echo    else magbox("Error! The folder is larger than 100GB") >>"%curr_dir%calc_1.vbs"
  57. echo    End If                                                >>"%curr_dir%calc_1.vbs"
  58. echo  End If                                                  >>"%curr_dir%calc_1.vbs"
  59. echo  '                                                       >>"%curr_dir%calc_1.vbs"
  60. echo  set fso=createobject("scripting.filesystemobject")      >>"%curr_dir%calc_1.vbs"
  61. echo  set fw=fso.createtextfile("c:\vbs_result.txt")          >>"%curr_dir%calc_1.vbs"
  62. echo  fw.write str1                                           >>"%curr_dir%calc_1.vbs"
  63. echo  fw.write "GB---"                                        >>"%curr_dir%calc_1.vbs"
  64. echo  'MsgBox(a3)                                             >>"%curr_dir%calc_1.vbs"
  65. for /f "usebackq delims=" %%i in ("directory.txt") do (
  66. echo dir_is %%i;
  67. for /f "usebackq tokens=3 delims= " %%j in (`dir /s /a /-c "%%i" ^|findstr 个文件`) do (
  68. setlocal enabledelayedexpansion
  69.   set z=%%j
  70.   )
  71. echo 总大小:!z!字节
  72.     if not exist "%curr_dir%calc_1.vbs" ( rem 处理父目录存在感叹号的路径,如果父目录的路径中存在感叹号,会被丢掉,因为开启了变量延迟。
  73.    
  74.     setlocal DISABLEDELAYEDEXPANSION
  75.     echo parent folder not exist ....... because it contails !!
  76.     copy "%curr_dir%calc_1.vbs" d:\
  77.     endlocal
  78.    
  79.     call "d:\calc_1.vbs" !z! %GB%
  80.    
  81.     setlocal DISABLEDELAYEDEXPANSION
  82.     echo "%curr_dir%dir_size.txt"
  83.     echo %%i >>"%curr_dir%dir_size.txt"
  84.        type c:\vbs_result.txt  |findstr .* >>"%curr_dir%dir_size.txt"
  85.        endlocal
  86.       
  87.     ) else (
  88.        call "%curr_dir%calc_1.vbs" !z! %GB%
  89.    
  90.        type c:\vbs_result.txt
  91.        echo %%i >>"%curr_dir%dir_size.txt"
  92.        type c:\vbs_result.txt  |findstr .* >>"%curr_dir%dir_size.txt"
  93.     )
  94.   
  95.   endlocal
  96.   
  97.   for /f "usebackq delims=" %%j in ("c:\vbs_result.txt") do (
  98.    set dir_total_size=%%j
  99.    setlocal DISABLEDELAYEDEXPANSION
  100.      rename "%%i" "%%j%%i"
  101.    endlocal
  102.   )
  103.   echo.
  104.   echo ------------------------------------------------------------------------------------------------------
  105. )
  106. setlocal DISABLEDELAYEDEXPANSION
  107. del /f /s /q "%curr_dir%calc_1.vbs"  >nul 2>nul
  108. del /f /s /q "c:\vbs_result.txt"  >nul 2>nul
  109. del /f /s /q "%curr_dir%directory.txt"  >nul 2>nul
  110. del /f /s /q "d:\calc_1.vbs"  >nul 2>nul
  111. endlocal
  112. pause
复制代码

作者: PowerShell    时间: 2014-4-19 19:34

杰森·斯坦森-暂告安全\[暂告安全].mkv
我们曾是战士\我们%曾是战士.mkv

请问,这样的文件名灵么?
作者: gflrlm    时间: 2014-4-20 10:07

回复 2# PowerShell

是可以的, 刚才试了下如下的文件名,也是ok的

目录名字:   123%&&--!dir_t{ot[]al_size!!dir_%total_s$%^&!@ize!000GB---[啊啊啊啊啊].Am%997).xvid]
作者: apang    时间: 2014-4-21 19:07

目测 可以不用开启变量延迟,把!z!换成 %%j
目测 第6行 set /a 溢出
作者: gflrlm    时间: 2014-4-22 11:07

回复 4# apang

第六行没用到,哈哈。
可以不用!z! 而直接使用%%j,前提是那段if else要放在第二层for 循环里面。

另外在英文版的windows操作系统里, 需要把82行替换成下面的代码:
        for /f "usebackq tokens=3 delims= " %%j in (`dir /s /a /-c "%%i" ^|findstr File^(s^)`) do (
作者: CrLf    时间: 2014-4-22 23:18

vbs 可以直接获取 subfolder.Size
http://bbs.bathome.net/viewthread.php?tid=25682
作者: gflrlm    时间: 2014-4-23 00:23

还是VBS强大,批处理只能用dir获取大小。。
作者: gflrlm    时间: 2014-4-23 00:36

回复 6# apang

这代码写的。。。 批处理调用vbs本身,跟shell调perl脚本有异曲同工之妙 /usr/bin/sh a.pl

a.pl
  1. : #-Perl-*
  2. 'exec perl -w -S $0 ${1+ $@ }'
  3. if 0
  4. ...
  5. ...
复制代码

作者: apang    时间: 2014-4-23 11:38

回复 8# gflrlm


    好吧,发现不应该在lz的帖子里贴代码,呵呵,已删除
作者: terse    时间: 2014-4-24 19:29

我来贴个  即使纯p也不用这么复杂吧
  1. @echo off
  2. set /p p="请选择要计算的目录类型,1是只取第一层目录,2是递归当前目录,默认是第一层目录"
  3. if %p% equ 2 (set "_dir=dir /ad/b/s^|sort /r") else set "_dir=dir /ad/b"
  4. setlocal enabledelayedexpansion
  5. set l=00000000&for /l %%i in (1 1 2) do set "l=!l!!l!"
  6. endlocal&set l=%l%
  7. set "var=64 32 16"
  8. set /amd=1048576,w=32,len=0
  9. set "mdl=%l:~9%%md%00"
  10. for /f "delims=" %%a in ('%_dir%') do (
  11.     set "fullname=%%a"&set "name=%%~nxa"
  12.     setlocal enabledelayedexpansion
  13.     for %%i in ("!fullname!\*") do set "size=%%~zi00"
  14.     set "s=!l!!size!"
  15.     if "!s:~-%w%!" geq "!mdl!" (
  16.        set "s=!size!"
  17.        if "!s:~16!" neq "" set len=16&set "S=!S:~16!"
  18.        set s=!s!FEDCBA9876543210&set/a "Len+=0x!s:~16,1!"
  19.        set/a "remainder=!Size:~,8!%%Md,GKB=!Size:~,8!/Md"
  20.        for /l %%i in (8 1 !Len!) do (
  21.            set/a "quotient=!remainder!!Size:~%%i,1!/Md,remainder=!remainder!!size:~%%i,1!%%Md"
  22.            set "GKB=!GKB!!quotient!"
  23.         )
  24.         if !GKB! geq 102400 (
  25.            set /a GKB/=1024
  26.            IF !GKB! GEQ 102400 (
  27.               set /a GKB=!GKB!/1024
  28.               set GKB=!GKB:~,-2!.!GKB:~-2!  TB--
  29.            ) else set GKB=!GKB:~,-2!.!GKB:~-2! GB--
  30.         )else set GKB=!GKB:~,-2!.!GKB:~-2!  MB--
  31.     ) else if !size! geq 102400 (
  32.                set /a GKB=!size!/1024
  33.                set GKB=!GKB:~,-2!.!!GKB:~-2! KB--
  34.             ) else if !size! geq 1024 (
  35.                       set /a GKB=!size!/1024
  36.                       set GKB=0.!GKB! KB--
  37.                    ) else set GKB=!size:~,-2! Byte--
  38.      ren "!fullname!" "!GKB!!name!"
  39.      endlocal
  40. )
  41. pause
复制代码

作者: gflrlm    时间: 2014-4-25 02:41

回复 10# terse

这个代码应该是没有测试 直接贴上来的吧。。
作者: PowerShell    时间: 2014-4-25 16:14

我也来pk了,哈哈。    http://www.bathome.net/thread-25678-1-1.html

不论性能还是代码简洁度,包赢bat,不输vbs!

还是那个结论:
学一年powershell等于学3年vbs,学5年bat。
bat=库简陋=代码复杂
自己学bat,不学powershell=坑自己
向他人传授bat,不向他人传授powershell=告诉他人公交坐法,不告诉人地铁坐法=坑人!
作者: terse    时间: 2014-4-25 20:10

回复 11# gflrlm
这是我这边情况 你那边情况不清楚了
作者: techon    时间: 2014-10-22 22:30

错误处理的想法不错,
判断变量保存的当前目录是否存在,
如果不存在,那肯定是路径中含有叹号被变量延迟给丢掉了。。。
作者: CrLf    时间: 2014-10-22 23:05

卧勒个槽,撸主的字幕真大...
f:\01movie\1.21GB---决斗犹马镇\决斗犹马镇.srt





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