返回列表 发帖

[文件操作] 批处理统计文件夹内的图片视频,计算大小时如何统计单位为G

@echo off
setlocal enabledelayedexpansion
for /d %%a in (*) do (
    set/a p=v=z=0
    pushd "%%a"
    for %%b in (*.jpg *.png *.bmp) do (
        rem 计算放在这里,就是对所有图片大小的计算
        set/a z+=%%~zb
        if not "%%~nb"=="000" if not "%%~nb"=="00.1" if not "%%~nb"=="00.2" if not "%%~nb"=="00.3" (
            set/a p+=1
        )
    )
    for %%c in (*.mp4 *.avi *.mov *.mkv) do (
        set/a v+=1,z+=%%~zc
    )
    set/a "sizeMB=z>>20"
    set "sizeUnit=M"
    if !sizeMB! geq 1024 (
        set/a "sizeGB=sizeMB>>10"
        set "sizeUnit=G"
    )
    popd
    if !v! equ 0 (
        rem 没有视频,只有图像
        if "!sizeUnit!"=="G" (
            ren "%%a" "%%a [!p!P-!sizeGB!!sizeUnit!]"
        ) else (
            ren "%%a" "%%a [!p!P-!sizeMB!!sizeUnit!]"
        )
    ) else if !p! equ 0 (
        rem 没有图像,只有视频
        if "!sizeUnit!"=="G" (
            ren "%%a" "%%a [!v!V-!sizeGB!!sizeUnit!]"
        ) else (
            ren "%%a" "%%a [!v!V-!sizeMB!!sizeUnit!]"
        )
    ) else (
        rem 既有图像又有视频
        if "!sizeUnit!"=="G" (
            ren "%%a" "%%a [!p!P!v!V-!sizeGB!!sizeUnit!]"
        ) else (
            ren "%%a" "%%a [!p!P!v!V-!sizeMB!!sizeUnit!]"
        )
    )
)
pauseCOPY
在这段代码中,脚本会统计当前文件夹下每一个子文件夹中的图像和视频的数量以及总大小,并将结果写在文件夹名称的后面,基本符合我的需求,但是早些时候统计文件夹大小时有时候大小会超过一个G,最后计算大小时单位他仍写成M,我使用了chatgpt,希望在统计大小时如果文件夹的内容超过一个G那么就以G为单位,但不知是我表述的有问题还是怎么样,这段代码里当文件内容超过一个计时它就记为1G,但是无论多大都记为1G,我希望能修改成超过1G时单位记为G,有多大就记为多大,比方说如果是1.46G就记为1.46G,不知道是否可行拜托各位大佬了

本帖最后由 aloha20200628 于 2024-8-7 20:52 编辑

回复 1# walkercolin

以下代码存为 test.bat 置于图片和视频文件所在目录下运行...
批处只能处理不超过2GB的文件尺寸值,超出此限须调用外部计算方法解决,以下代码调用powershell方法(仅因其句式简捷)
运行结果会对每个目标目录更名,其更名格式》“原目录名 [xxxPyyyV-zzzMB]” 或 “原目录名 [xxxPyyyV-zzzGB]”,其中 xxx 或 yyy 可能=0(对应图片或视频文件数量=0)
@echo off &setlocal enabledelayedexpansion &for /d %%d in (*) do (
pushd "%%d" &set/a "np=0,zp=0,nv=0,zv=0"
for /f "tokens=1-2 delims=个文件 " %%a in (
'2^>nul dir /a-d/-c *.jpg *.png *.bmp^|find " 个文件 " ') do (set "np=%%a"&set "zp=%%b")
for /f "tokens=1-2 delims=个文件 " %%a in (
'2^>nul dir /a-d/-c *.mp4 *.avi *.mov *.mkv^|find " 个文件 " ') do (set "nv=%%a"&set "zv=%%b")
for /f %%v in (
' powershell "if((!zp!+!zv!) -lt 1gb){[math]::round(-(!zp!+!zv!)/1mb,2)}else{[math]::round((!zp!+!zv!)/1gb,2)}" ') do set "zpv=%%v"
if "!zpv:~0,1!"=="-" (set "zpv=!zpv:~1!MB") else (set "zpv=!zpv!GB")
popd & ren "%%~fd" "%%d [!np!P!nv!V-!zpv!]"
)
endlocal&pause&exit/bCOPY
1

评分人数

TOP

本帖最后由 77七 于 2024-8-8 01:10 编辑

批处理统计文件夹内图片、视频数量及大小,并重命名文件夹
@echo off
rem 保存为ansi编码
cd /d "%~dp0"
rem 排除特定文件(000,00.1,00.2,00.3),不需要可以删除下一行
set "_f=^|findstr /rvix /c:"00\.[123]\.[jpb][pnm][gp]" /c:"000\.[jpb][pnm][gp]""
(for /f "delims=" %%d in ('dir /b /ad') do (
setlocal
pushd "%%d"
for /f %%a in ('dir /b /a-d *.jpg *.png *.bmp %_f% ^|find /c /v ""') do (
set /a "1/%%a" && set P=%%aP
)
for /f %%a in ('dir /b /a-d *.mp4 *.avi *.mov *.mkv ^|find /c /v ""') do (
set /a "1/%%a" && set V=%%aV
)
for /f "tokens=3" %%i in ('dir /-c /a-d *.jpg *.png *.bmp *.mp4 *.avi *.mov *.mkv ^|findstr /iec:" 字节"') do (
for /f "tokens=1-2 delims=." %%a in ('powershell -c "$input = %%i; [math]::Round($input / (1024 * 1024 *1024), 2)"') do (
set /a "1/%%a" && set "Z=%%a.%%bG" || for /f "delims=." %%c in ('powershell -c "%%i/1024/1024"') do set Z=%%cM
)
)
popd
if defined Z (
call echo ren "%%d" "%%d [%%p%%%%V%%-%%Z%%]"
)
endlocal
)) 2>nul
pauseCOPY
1

评分人数

bat小白,请多指教!谢谢!

TOP

回复 2# aloha20200628
输出结果为[0P0V-0GB]

TOP

回复 3# 77七
输出结果为[0P0V-0GB]

TOP

本帖最后由 aloha20200628 于 2024-8-8 10:28 编辑

回复 4# walkercolin

更正》2楼批处代码应置于 ‘图片+视频子目录’ 的上一级目录中运行,如同一楼代码的运行位置
模拟一楼题型的文件及目录,用2楼代码已测试通过...

TOP

回复 5# walkercolin





0P0V0G这三个0在任何情况下都是不可能出现的
bat小白,请多指教!谢谢!

TOP

本帖最后由 ppll2030 于 2024-8-8 16:28 编辑

回复 1# walkercolin


    用set /a 的结果都是整数,而另一个问题,bat计算有2GB的限制,综合两点,你的计算方法需要换一个。
试试:把16行的  set/a "sizeMB=z>>20"  替换为:
for /f %%v in ('powershell "[math]::Round(!z! / (1073*1000), 2)"') do set "sizeMB=%%v"COPY
把19行的   set/a "sizeGB=sizeMB>>10"  替换为:
for /f %%v in ('powershell "[math]::Round(!z! / (1073*1000*1000), 2)"') do set "sizeGB=%%v"COPY

TOP

回复 8# ppll2030
有用的,但是这样一来,那些没达到1G的文件夹也仍然按照G的单位进行计算,我希望没超过1G的按M单位,超过的按G单位是否可行呢

TOP

本帖最后由 ppll2030 于 2024-8-8 18:34 编辑

回复 9# walkercolin


    你原来的代码是否能正常判断显示MB或GB?因为我没细看,我只是提供了计算方式的修改。
如果if的判断有误,那就还要修改,不如直接用楼上大佬的完整代码了

看了一下,if判断数值,不能有小数点。否则也会报错。
把16行的  set/a "sizeMB=z>>20"  替换为:
for /f %%v in ('powershell "[math]::Round(!z! / (1073*1000), 0)"') do set "sizeMB=%%v"COPY
保留整数,方便你的IF做判断。
19行,正常替换,保留两位小数。
这样应该没有问题了。
1

评分人数

    • walkercolin: 感谢给帖子标题标注[已解决]字样技术 + 1

TOP

本帖最后由 aloha20200628 于 2024-8-8 19:14 编辑

回复 1# walkercolin

      一楼代码中第8,14,16行,一旦文件尺寸值(字节单位)或累加值(字节单位)超过32位整数限就会失误,此乃为何要调用外部计算方法并重写代码的原因
      重写代码不仅是简单重复调用外部计算方法(尤其是在最内层循环体内复用其效率会明显降低),还要兼顾代码的效率,从dir简报中直接获取目标文件总数及其文件尺寸累加值,应该是一条捷径...

TOP

回复 10# ppll2030
完美了,感谢大佬帮助愚钝完全不懂什么代码的我拨云见雾,您简直就是当代丹尼斯·里奇,再次感谢您

TOP

回复 12# walkercolin


    嗯。楼上的大佬提醒了。你的前半段统计体积,还是用的set/a,所以2GB的限制还是存在的,建议更换dir来获取

TOP

只用bat,适合粗略统计。数值不准确,也无需保留小数点后两位了
@echo off
rem 保存为ansi编码
cd /d "%~dp0"
for %%a in ("000" "00.1" "00.2" "00.3") do (
set _"%%~a"=1
)
set -=-
for /f "delims=" %%d in ('dir /b /ad') do (
set f=%%d
setlocal enabledelayedexpansion
pushd "!f!"
for %%i in (*.jpg *.png *.bmp) do (
if not defined _"%%~ni" (
set /a p+=1
)
set /a m=%%~zi/1024,n+=m
)
set n/=1024
for %%i in (*.mp4 *.avi *.mov *.mkv) do (
set /a v+=1
set t=%%~zi
set t=!t:~0,-3!
if "!t!" neq "" (
set /a n+=!t!/1024
)
)
popd
for %%a in (P V) do (
if defined %%a (
set str=!str!!%%a!%%a
)
)
if !n! gtr 1024 (
set /a x=n/1024
echo ren "!f!" "!f![!str!-!x!G]"
) else if !n! neq 0 (
echo ren "!f!" "!f![!str!-!n!M]"
)
endlocal
)
pauseCOPY
bat小白,请多指教!谢谢!

TOP

本帖最后由 WHY 于 2024-8-14 11:50 编辑

Test.ps1
$srcFolder = 'E:\Test\';                  #源目录路径
$ext1 = @{'.jpg'=1; '.bmp'=1; '.png'=1; '.tif'=1; '.jpeg'=1} #图片扩展名
$name = @{'000'=1; '00.1'=1; '00.2'=1; '00.3'=1}             #需要排除的图片名称
$ext2 = @{'.mp4'=1; '.avi'=1; '.mov'=1; '.mkv'=1}            #视频扩展名
$Hash = @{}
Function Get-Size($sz) {
    If ($sz -ge 1GB) {
        return ($sz/1GB).ToString('0.00G');
    } ElseIf ($sz -ge 1MB) {
        return ($sz/1MB).ToString('0.00M');
    } Else {
        return ($sz/1KB).ToString('0.00K');
    }
}
forEach ($f In (Get-ChildItem -Literal $srcFolder -Recurse -File -Filter *.*)) {
    $fd = $f.DirectoryName;                       #目录名
    If ($ext1.Contains($f.Extension) -and !$name.Contains($f.BaseName)) {
        If (!$Hash.Contains($fd)) {
            $Hash.Add($fd, @(1, 0, $f.Length));   #添加哈希表,键=目录名;值=数组
        } Else {
            $Hash[$fd][0] += 1;                   #图片个数
            $Hash[$fd][2] += $f.Length;           #文件大小
        }
    } ElseIf ($ext2.Contains($f.Extension)) {
        If (!$Hash.Contains($fd)) {
            $Hash.Add($fd, @(0, 1, $f.Length));   #添加哈希表,键=目录名;值=数组
        } Else {
            $Hash[$fd][1] += 1;                   #视频个数
            $Hash[$fd][2] += $f.Length;           #文件大小
        }
    }
}
$keys = $Hash.GetEnumerator().Name;
[Array]::Sort($keys);                             #排序,避免重命名失败
for ($i=$keys.Count-1; $i -ge 0; $i--) {
    $k = $keys[$i];
    $sufFix = '[' + $Hash[$k][0] + 'P' + $Hash[$k][1] + 'V-' + (Get-Size $Hash[$k][2]) + ']';   #后缀
    $sufFix = $sufFix -replace '(?-i)(?<=\D)0[PV]';       #删掉0P、0V
    $newName = $k.Split('\')[-1] + $sufFix;
    Rename-Item -Literal $k -NewName $newName;            #重命名
}
pauseCOPY
1

评分人数

TOP

返回列表