Search code examples
windowsbatch-filewindows-10batch-processing

How to find m3u playlist filesize in batch script?


I'm trying to find the filesize of m3u playlist files in a directory. I don't know the correct syntax for batch script, so the below code might not run properly.

I need help regarding this script.

FOR /f %f in ('dir /b') DO {
  SET %filesize% = 0
  FOR /F %i in (%f) DO {
   If %i~1,1% equ ":" AND %i~2,1% equ "\" (%filesize% = %filesize% + %~z1)
  }
 echo %f [%filesize%] & echo. > PlaylistsList.txt
}
  1. First line scans the base directory for m3u files,
  2. Second line sets a variable filesize to 0, so that it doesn't keep getting added in each loop.
  3. The third line takes each m3u playlist file as a text file input for processing in another loop.
  4. Fourth line checks if the filepath format is in "C:\music\" format, by comparing the 2nd and 3rd character via : & \. Then filesize is added for each file found in the m3u playlist file.
  5. Finally the filename is echoed along with the filesize.

Hence the output in the PlaylistsList.txt:

Rock.m3u [900 mb]

Electronic.m3u [500 mb]

Acoustic.m3u [150 mb]


Solution

  • First, variable names in for loop in batch files must be preceded with 2 %s. So insert more percent signs to your variables. Second, put your blocks inside parentheses (), not {}


    Another problem is your set command. Variable name in set isn't surrounded by percent sign, and the assigned value must be right after the equal symbol, or your variable's real value will include the preceding spaces. The correct way is like this: SET filesize=0 or SET "filesize=0"

    You're also adding the filesize of the first parameter again and again (notice z1 there instead of zi

    %filesize% = %filesize% + %~z1
    

    You must get the size of the files in the list using %~zi and add it to the sum. However you can't do math directly like above. Use set /a instead

    set /a filesize += %%~zi
    

    And you're reading the m3u file content incorrectly. To read a line from a text file use this way

    for /F "tokens=*" %%L in (%%f) do [command]
    

    I don't understand your 4th this line. You want to check if the line begins in C:\music\ but you instead check if the second character is : and the 3rd one is \. There are several problems with this:

    • IF doesn't support multiple conditions like AND
    • You can't substring a variable in for loop, because it isn't surrounded by percent signs like normal variables.

    To substring, assign the value to a normal variable first: set line=%%L. To check for both conditions there are several workarounds like this, but your case is just checking for a single string so you don't need to check for separate characters. Use if "!line:~1,2!"==":\" if you want the behavior above, or if /i "!line:~0,2!"=="C:\music\" to check for the folder you mentioned, use /i for case insensitive check. Variables in the for loop must be surrounded with !! to make it expand at runtime. Remember to use setlocal EnableDelayedExpansion at the beginning.

    At the end you don't need to & echo. because echo always put a newline after printing. But you must use >> to append the output file, or it'll erase the old content every time you redirect echo.


    Now to make filesize you need to do the math yourself because filesize is just a numerical value. Note that there's no unit for data size called mb. Divide by 1024 if you want MiB (MB in Windows term) and divide by 1000 to get MB.

    So the script should looks like this

    setlocal EnableDelayedExpansion
    
    for /f %%f in ('dir /b') DO (
        set filesize=0
        for /F "tokens=*" %%L in (%%f) do (
            set line=%%L
            if "!line:~1,2!"==":\" set /a filesize += %%~zL
        )
    )
    set /a filesize /= 1024
    echo %%f [%filesize% MB] >> PlaylistsList.txt
    

    Bonus: If a rounded file size result is desired, use

    set divisor=1024
    set /a filesize = (%filesize% + %divisor%/2) / %divisor%
    

    Edit:

    To accommodate for long file names, the second for loops should be used with usebackq like this

    for /F "usebackq tokens=*" %%L in ('%%f') do (
    

    Another way is calling another function to get file size

    set line=%%L
    CALL :FileSize "%%L"
    if "!line:~1,2!"==":\" set /a filesize += %%~zL
    
    :FileSize
    SET filesize=%~z1
    

    One important note is that variables used in set are 32-bit signed int, so it won't work if the total size exceeds 2GB.