Get size of a directory in 'MB' using batch file

后端 未结 4 1501

I want to get the size of directory say C:\\Temp in MB using batch file. I don\'t need sizes of child directories or files, but the size of directo

4条回答
  •  野趣味
    野趣味 (楼主)
    2020-11-27 08:33

    Here is a pure batch file solution (refer to the remarks in the code for some brief explanations):

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    
    rem Define constants here:
    set /A DIVISOR=1024 & rem (1024 Bytes = 1 KBytes, 1024 KBytes = 1 MByte,...)
    set "ROUNDUP=#" & rem (set to non-empty value to round up results)
    
    rem Get size of directory given as command line argument:
    for /F "tokens=2 delims=: " %%B in ('
        robocopy "%~1" "%~1" "*.*" /L /S /XJ /BYTES /NP /NFL /NDL /NJH ^| ^
            find /I "Bytes"
    ') do set "BYTES=%%B"
    if not defined BYTES set "BYTES=0"
    rem Display result in Bytes and divide it to get KBytes, MBytes, etc.:
    call :DIVIDE %BYTES% 1 RESULT
    echo( Bytes:    %RESULT%
    call :DIVIDE %RESULT% %DIVISOR% RESULT REST
    if defined ROUNDUP if 0%REST% GTR 0 set /A RESULT+=1
    echo(KBytes:    %RESULT%
    call :DIVIDE %RESULT% %DIVISOR% RESULT REST
    if defined ROUNDUP if 0%REST% GTR 0 set /A RESULT+=1
    echo(MBytes:    %RESULT%
    call :DIVIDE %RESULT% %DIVISOR% RESULT REST
    if defined ROUNDUP if 0%REST% GTR 0 set /A RESULT+=1
    echo(GBytes:    %RESULT%
    
    endlocal
    exit /B
    
    
    :DIVIDE val_dividend val_divisor [ref_result] [ref_remainder]
    rem Divide a huge number exceeding the 32-bit limitation
    rem by a 32-bit number in the range from 1 to 1000000000;
    rem the result might also exceed the 32-bit limitation.
    setlocal EnableDelayedExpansion
    set "DIVIDEND=%~1"
    set "DIVISOR=%~2"
    set "QUOTIENT=%~3"
    set "REMAINDER=%~4"
    
    rem Check whether dividend and divisor are given:
    if not defined DIVIDEND (
        >&2 echo(Too few arguments, dividend missing^^!
        exit /B 2
    ) else if not defined DIVISOR (
        >&2 echo(Too few arguments, divisor missing^^!
        exit /B 2
    )
    rem Check whether dividend is purely numeric:
    for /F "tokens=* delims=0123456789" %%N in ("!DIVIDEND!") do (
        if not "%%N"=="" (
            >&2 echo(Dividend must be numeric^^!
            exit /B 2
        )
    )
    rem Convert divisor to numeric value without leading zeros:
    for /F "tokens=* delims=0" %%N in ("%DIVISOR%") do set "DIVISOR=%%N"
    set /A DIVISOR+=0
    rem Check divisor against its range:
    if %DIVISOR% LEQ 0 (
        >&2 echo(Divisor value must be positive^^!
        exit /B 1
    ) else if %DIVISOR% GTR 1000000000 (
        >&2 echo(Divisor value exceeds its limit^^!
        exit /B 1
    )
    set "COLL=" & set "NEXT=" & set /A INDEX=0
    rem Do a division digit by digit as one would do it on paper:
    :LOOP
    if "!DIVIDEND:~%INDEX%,1!"=="" goto :CONT
    set "NEXT=!NEXT!!DIVIDEND:~%INDEX%,1!"
    rem Remove trailing zeros as such denote octal numbers:
    for /F "tokens=* delims=0" %%N in ("!NEXT!") do set "NEXT=%%N"
    set /A NEXT+=0
    set /A PART=NEXT/DIVISOR
    set "COLL=!COLL!!PART!"
    set /A NEXT-=PART*DIVISOR
    set /A INDEX+=1
    goto :LOOP
    :CONT
    rem Remove trailing zeros as such denote octal numbers:
    for /F "tokens=* delims=0" %%N in ("%COLL%") do set "COLL=%%N"
    if not defined COLL set "COLL=0"
    rem Set return variables or display result if none are given:
    if defined QUOTIENT (
        if defined REMAINDER (
            endlocal
            set "%REMAINDER%=%NEXT%"
        ) else (
            endlocal
        )
        set "%QUOTIENT%=%COLL%"
    ) else (
        endlocal
        echo(%COLL%
    )
    exit /B
    

    Basically, the size of the contents of the directory given as command line argument is gathered by robocopy, similar to npocmaka's approach; the resulting size in Bytes is stored in variable BYTES.

    Afterwards, several subroutine calls are done, each to divide the result by 1024 in order to get the size in KBytes, then MBytes and GBytes.

    The values resulting from the divisions are incremented by 1 if there is a remainder in order to round up the sizes (similar to Windows Explorer, which for example displays 1 KB for very small files). You can disable this feature by setting variable ROUNDUP to an empty string, which leads to rounding down.


    Division Approach

    Since the set /A command (and its division operator /) can handle (signed) 32-bit integers only, the subroutine :DIVIDE performs the actual division like one would do it on paper. The dividend (that is the number to be divided) is treated as a string, so the 32-bit range can be exceeded; the divisor (that is the number to divide by) however must not exceed it; rather it must be in the range from 1 to 1000000000. The loop at :LOOP consisting of goto :LOOP and a conditional goto :CONT constitutes a while-loop-like structure that iterates through all the decimal figures of the dividend and terminates after the last one has been reached.

    The subroutine expects at least two arguments -- the values of the dividend and the divisor. It accepts even two more -- the name of a variable to hold the quotient (that is the division result) and another one to hold the remainder. If no optional arguments are given, the quotient is displayed on the console.

提交回复
热议问题