0

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]

phuclv
  • 37,963
  • 15
  • 156
  • 475
mk117
  • 753
  • 2
  • 13
  • 26
  • you want to get the sum of the sizes of the files in the playlist? – phuclv Mar 29 '16 at 09:38
  • Yes! I'm trying to get the total filesize of the music playlist. – mk117 Mar 29 '16 at 09:47
  • 1
    1. Do not guess the syntax, learn it! enter `for /?` in a command prompt window to learn how it works; do the same for `set` and `if`. 2. There are no keywords like `AND` and `OR`; however, you could do something like `if a EQU 1 if b EQU 2 ...` to create a logical `AND`. – aschipfl Mar 29 '16 at 10:09
  • Ok. Thanks! I'll try and learn the syntax from the command prompt. – mk117 Mar 29 '16 at 10:11

2 Answers2

2

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.

phuclv
  • 37,963
  • 15
  • 156
  • 475
  • Thanks Luu! A slight problem, I'm getting an appended output of `%f [0 MB]` in my txt file, and via `pause` I found out that since my m3u filenames have spaces, therefore the script is not able to find the m3u files! Error: `Cannot find the file "Folder"` (while my m3u files might be `Folder 1`.. I tried `set f="f"` before the second for loop, and still the error appears. – mk117 Mar 29 '16 at 11:06
  • ah you need `set f="%%f"` and then use `%f%` instead – phuclv Mar 29 '16 at 11:19
  • Well, I didn't understand that. I solved it by adding `"tokens=* delims="` to for loops. Also, another question is that the batch script is not treating the `.m3u` files as text. The filename appears in the echo, but the `%%L` is displayed with only `%L`, m3u filename appears although the file is not opened by the script. The `%%f` in the second for loop is being treated as a string, not a file. – mk117 Mar 29 '16 at 11:42
  • Hi! I finally got the script working... I'm about to post it as an answer, please correct your code as per that script, so that I can select your answer as the answer to this question! Thanks! – mk117 Mar 29 '16 at 12:16
  • Well, [useback](http://stackoverflow.com/questions/27090735/how-to-use-nested-for-loops-in-batch-files) solved the issue of filename being treated as string via the question page linked in this comment. – mk117 Mar 29 '16 at 12:18
  • it should be `usebackq` although I don't know why useback also works – phuclv Mar 29 '16 at 12:21
1

Corrected from Luu's Answer!

setlocal EnableDelayedExpansion

for /f "tokens=* delims=" %%f in ('dir *.m3u /b') DO (
    set filesize=0
    REM set var1="%%f"
    REM echo %var1%
    for /f "useback tokens=* delims=" %%L in ("%%~f") do (
        set line=%%L
        if "!line:~1,2!"==":\" set /a filesize += %%~zL
    )
    REM set /a filesize /= 1024
    echo %%f [!filesize! MB] >> PlaylistsList.txt
)
pause
phuclv
  • 37,963
  • 15
  • 156
  • 475
mk117
  • 753
  • 2
  • 13
  • 26
  • no need to put filesize in `!!` because you aren't changing it's value in a loop anyway – phuclv Mar 29 '16 at 12:28
  • Well, the filesize wasn't showing up in the text size, so I read your explanation about how variables could be enclosed between double `!!` marks. – mk117 Mar 29 '16 at 12:30
  • I forgot you're putting size inside the outside loop – phuclv Mar 29 '16 at 12:31