Help with File Size Calculations

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Help with File Size Calculations

#1 Post by julesverne » 12 Jan 2014 13:24

Hi all, I found this cool bat code to parse out larger than 32 byte numbers. http://ss64.org/viewtopic.php?id=288#p884

It takes a file size number like.. 999999999999999999999999999999 and turns it in TB GB MB KB B

What I'd like to do is take any file, no matter what size. have it give me the size output using the script the link has. Then take the total disk space available on a drive using the above method. Then.. subtract the file size output from the total diskspace output to see if it has enough free space to copy. I like this method cause I think it's pretty accurate down to the byte.

I'm not sure how to do this and I imagine if I did figure it out it would be convoluted code that would make it slower than it needs to be.

Thanks in advance!

Jules

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Help with File Size Calculations

#2 Post by Aacini » 12 Jan 2014 16:01

The code at the indicated link does not manage big numbers; it will fail if the parameter is a number larger than 32-bits.

I got the program at this post and modified it in order to convert an unlimited size decimal number into a base 1024 number (instead of a binary one). This way, the result is the equivalent number of Bytes + KB + MB + GB + TB + etc. of the decimal number. The result is given as an array of factors that is useful for compare a pair of numbers, for example, but that may be easily converted to a standard message.

EDIT: Small bug fixed. I also added an optional second parameter with the name of the array that receive the result.

Code: Select all

@echo off
setlocal EnableDelayedExpansion

rem DecimalToPowerOf1024.bat bigNumber [arrayName]
rem Decimal to power-of-1024 base conversion of an unlimited size decimal number
rem Antonio Perez Ayala

rem Get the name of the array, if any
set power=PowerOf1024
if "%~2" neq "" set "power=%~2"

rem Divide the number in 9-digits groups, eliminating left zeros in each group
set number=%1
set groups=0
:nextGroup
   set group=%number:~-9%
   for /L %%a in (1,1,8) do if "!group:~0,1!" equ "0" set group=!group:~1!
   set /A groups+=1
   set group[%groups%]=%group%
   set number=%number:~0,-9%
if defined number goto nextGroup

rem Convert the 9-digits groups to power-of-1024 values
set /A bitPos=0, %power%=0, %power%[0]=0
:nextBinaryDigit
   rem Divide the 9-digits groups by 2
   set carry=0
   for /L %%i in (%groups%,-1,1) do (
      set /A term=carry*1000000000+group[%%i], group[%%i]=term/2, carry=term%%2
   )
   rem Insert remainder in current PowerOf1024 value, in right-to-left order
   set /A "%power%[!%power%!]+=carry<<bitPos, bitPos+=1"
   rem If current PowerOf1024 value completed: pass to next one
   if %bitPos% equ 10 set /A bitPos=0, %power%+=1 & set %power%[!%power%!]=0
   rem If last (most significant) group was completely converted: eliminate it
   if !group[%groups%]! equ 0 set /A groups-=1
   rem And pass to convert the rest of 9-digits groups
if %groups% gtr 0 goto nextBinaryDigit
for %%p in (!%power%!) do if !%power%[%%p]! equ 0 set "%power%[%%p]=" & set /A %power%-=1

set %power%


Antonio
Last edited by Aacini on 12 Jan 2014 18:10, edited 1 time in total.

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#3 Post by julesverne » 12 Jan 2014 16:48

So.. Can you please help me to understand the output a little?

H:\TEST>set $filename="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"

H:\TEST>for %F in ("C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob") do set "$size=%~zF"

H:\TEST>set "$size=1491345408"

H:\TEST>CALL "H:\TEST\filesizecompare.bat" 1491345408
Press any key to continue . . .
power=2
PowerOf1024[0]=513
PowerOf1024[1]=597
PowerOf1024[2]=468
Press any key to continue . . .

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#4 Post by julesverne » 12 Jan 2014 17:19

Also, how would i use this output to compare against another? i.e. filesize compared to available drive space.

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Help with File Size Calculations

#5 Post by Aacini » 12 Jan 2014 18:39

The original code had a small bug! :oops: Copy the code above again, please...

Code: Select all

C:\> DecimalToPowerOf1024.bat 1491345408
PowerOf1024=3
PowerOf1024[0]=0
PowerOf1024[1]=264
PowerOf1024[2]=398
PowerOf1024[3]=1

Previous result indicate that the decimal number 1491345408 is equal to 0 Bytes + 264 Kb + 398 Mb + 1 Gb.

I added an optional second parameter that define the name of the variables (last index and array) that receive the result, so you may directly store the result in different variables in order to compare they. For example:

Code: Select all

set filesize=value of filesize
call :DecimalToPowerOf1024 %filesize% file

set availableSpace=value of available space
call :DecimalToPowerOf1024 %availableSpace% drive


rem Test if availableSpace in drive is greater than filesize:

rem If there are more groups of numbers in drive than in file
if %drive% gtr %file% goto enoughSpace

rem If there are the same groups of numbers and drive number is greater than file number
if %drive% equ %file% if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace

echo Not enough space


Let me know if this solution works correctly

Antonio

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#6 Post by julesverne » 12 Jan 2014 19:49

Thanks for the clarification on how to read the output and code. Two issues are occurring now after putting the two codes you supplied together.

This is the code:

Code: Select all

@echo on
set file="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"
set drive="%~d0"


for %%F in (%file%) do set "filesize=%%~zF"
for %%F in (%drive%) do set "availableSpace"=%%~zF"

call :DecimalToPowerOf1024 %filesize% %file%

call :DecimalToPowerOf1024 %availableSpace% %drive%


rem Test if availableSpace in drive is greater than filesize:

rem If there are more groups of numbers in drive than in file
if %drive% gtr %file% goto enoughSpace

rem If there are the same groups of numbers and drive number is greater than file number
if %drive% equ %file% if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace

echo Not enough space
pause
:DecimalToPowerOf1024


setlocal EnableDelayedExpansion

rem DecimalToPowerOf1024.bat bigNumber [arrayName]
rem Decimal to power-of-1024 base conversion of an unlimited size decimal number
rem Antonio Perez Ayala

rem Get the name of the array, if any
set power=PowerOf1024
if "%~2" neq "" set "power=%~2"

rem Divide the number in 9-digits groups, eliminating left zeros in each group
set number=%1
set groups=0
:nextGroup
   set group=%number:~-9%
   for /L %%a in (1,1,8) do if "!group:~0,1!" equ "0" set group=!group:~1!
   set /A groups+=1
   set group[%groups%]=%group%
   set number=%number:~0,-9%
if defined number goto nextGroup

rem Convert the 9-digits groups to power-of-1024 values
set /A bitPos=0, %power%=0, %power%[0]=0

:nextBinaryDigit
   rem Divide the 9-digits groups by 2
   set carry=0
   for /L %%i in (%groups%,-1,1) do (
      set /A term=carry*1000000000+group[%%i], group[%%i]=term/2, carry=term%%2
   )
   rem Insert remainder in current PowerOf1024 value, in right-to-left order
   set /A "%power%[!%power%!]+=carry<<bitPos, bitPos+=1"
   rem If current PowerOf1024 value completed: pass to next one
   if %bitPos% equ 10 set /A bitPos=0, %power%+=1 & set %power%[!%power%!]=0
   rem If last (most significant) group was completely converted: eliminate it
   if !group[%groups%]! equ 0 set /A groups-=1
   rem And pass to convert the rest of 9-digits groups
if %groups% gtr 0 goto nextBinaryDigit
for %%p in (!%power%!) do if !%power%[%%p]! equ 0 set "%power%[%%p]=" & set /A %power%-=1

set %power%
GOTO :EOF


This is the OUTPUT

Code: Select all

H:\TEST>set file="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"

H:\TEST>set drive="H:"

H:\TEST>for %F in ("C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob") do set "filesize=%~zF"

H:\TEST>set "filesize=1491345408"

H:\TEST>for %F in ("H:") do set "availableSpace"=%~zF"

H:\TEST>set "availableSpace"=4096"

H:\TEST>pause
Press any key to continue . . .


Issue #1. after i press a key I can see that it is saying "missing operator" EDIT: IT ERRORS AND EXITS OUT
Issue #2. is this bit of code at the top,

Code: Select all

for %%F in (%drive%) do set "availableSpace"=%%~zF"
Using that code the output says drive H: is 4096 which.. I don't really understand why, nor do i understand what that number is. The file size is correct using %~zF According to windows explorer properties it's 455 GB available space.

I don't know if it matters that I put both pieces of your code together in one bat file, which I feel is a bit better.

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Help with File Size Calculations

#7 Post by foxidrive » 13 Jan 2014 00:44

This batch file can be passed a file such as: CalcFilesize.bat "%userprofile%\Videos\movie\VIDEO_TS\all.vob"

and it will return yes or no in %result% to tell you if there is enough space on the current drive for it.

It's not tested

Code: Select all

@echo off
set filesize=%~z1
for /f "tokens=3" %%a in ('dir /-p /-c ^|find " bytes free"') do set calc=%%a-%filesize%
echo %calc%
>"%temp%\VBS.vbs" echo Set fso = CreateObject("Scripting.FileSystemObject")
>>"%temp%\VBS.vbs" echo if (%calc%) ^> -1 then wscript.echo "yes" else wscript.echo "no"
for /f "delims=" %%a in ('cscript /nologo "%temp%\VBS.vbs"') do set "result=%%a"
del "%temp%\VBS.vbs"
echo %result%

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#8 Post by julesverne » 13 Jan 2014 11:44

This batch file can be passed a file such as: CalcFilesize.bat "%userprofile%\Videos\movie\VIDEO_TS\all.vob"

and it will return yes or no in %result% to tell you if there is enough space on the current drive for it.

It's not tested.


Hi Foxidrive, thanks! Unfortunately, the reason this won't work for me is the Windows 32 bit size limit. So Aacini came up with a way to manage the big numbers into groups. For instance I'll be using this bat to see if a file will fit onto a server (which will have a big number) or a TB external drive (which will also have a big number.

I had a couple issues with the last 2 bits of code Aacini came up with when I merged them together.

Issue #1. after i press a key I can see that it is saying "missing operator" EDIT: IT ERRORS AND EXITS OUT
Issue #2. is this bit of code at the top,

Code: Select all

for %%F in (%drive%) do set "availableSpace"=%%~zF"


Using that code the output says drive H: is 4096 which.. I don't really understand why, nor do i understand what that number is. The file size is correct using %~zF According to windows explorer properties it's 455 GB available space.



That last bit I quoted myself I realized doesn't sound very clear. Using that code the output says drive H: is 4096 using the standard %%~zF but looking at windows explorer properties it says the drive is 455 GB of available space.. so I don't understand where CMD is coming up with 4096 for %%~zF

Endoro
Posts: 244
Joined: 27 Mar 2013 01:29
Location: Bozen

Re: Help with File Size Calculations

#9 Post by Endoro » 13 Jan 2014 18:58

You do not need VB nor math to compare big numbers in Batch:

Code: Select all

@ECHO OFF &SETLOCAL
if "%~1"=="" echo(Missing file name.&exit /b 1
if not exist "%~1" echo(File not found: "%~1".&exit /b 1
for /f %%a in ("%~1") do set "fileattrib=%%~aa"
if "%fileattrib:~0,1%"=="d" echo("%~1" is directory.&exit /b 1
set "filesize=%~z1"
if "%filesize%"=="0" echo("%~1": file size is zero.&exit /b 1
for /f "tokens=2delims=:" %%a in ('fsutil volume diskfree %cd:~0,2%') do for %%b in (%%~a) do set "diskfree=%%~b"
echo(File size: %filesize% byte(s) in "%~1"
echo(Disk free: %diskfree% byte(s) on %cd:~0,2%
set "prefix=000000000000000"
set "filecompare=%prefix%%filesize%"
set "filecompare=%filecompare:~-15%"
set "diskcompare=%prefix%%diskfree%"
set "diskcompare=%diskcompare:~-15%"
for /f "tokens=1*delims==" %%a in ('(set diskcompare^&set filecompare^) ^|sort') do set "result=%%b"
<nul set /p "=You can "
if "%result%"=="%diskcompare%" <nul set /p "=NOT "
echo(copy "%~1" to %cd:~0,2%

penpen
Expert
Posts: 2009
Joined: 23 Jun 2013 06:15
Location: Germany

Re: Help with File Size Calculations

#10 Post by penpen » 13 Jan 2014 19:55

Another possibility is, to use the 1. http://en.wikipedia.org/wiki/Intercept_theorem to shorten the numbers:
Use |SA|:|SB|==|SC|:|SD| to scale the filesizes to smaller numbers.

For example the dir command may give you these sizes:
- HDD free space |SB| := 111,222,333,444
- file size |SD| := 888,777,666

In addition use a ratio of 1000 == |SA|:|SB|

Then you get as a results (in int32 values, a little rounding error):
- |SA|==111,222,333
- |SC|==888,777

As you see the ratios haven't changed.

penpen

PS: It is similar to Endoros solution (also based on the 1. IT), but he exceeded the digits, instead of shortening them.

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Help with File Size Calculations

#11 Post by Aacini » 13 Jan 2014 21:09

@julesverne:

I assumed from your first post that you knew how to take the total disk space available on a drive and the size of a file, and that you asked for help in the comparison of big numbers...

Your guessing that "for %%F in (%~d0) do set "availableSpace=%%~zF" return the available space in a drive have no base. Why this method could not return the occupied or total space in a drive? I have not found a single reference on the meaning of "%%~z" modifier when it is used on a drive; in my computer it returns 28672 (?). You may get the available space in a drive from the third token in the last line of DIR command:

Code: Select all

for /F "tokens=3" %%F in ('dir /-C "%~N0.bat"') do set "availableSpace=%%F"

Note also that your code have several small errors:

  • for %%F ... set "availableSpace"=%%~zF" command have an additional quote before the equal sign.
  • If there is a "goto enoughSpace" command, then must be the :enoughSpace label.
  • The main program requires a "setlocal EnableDelayedExpansion" command, because it execute: "if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace".
  • On the other hand, if you insert a "setlocal EnableDelayedExpansion" command at beginning of DecimalToPowerOf1024 subroutine, when the subroutine ends all variables created there will be deleted, so the main program will not recieve the calculated values.
  • You must insert a "goto :EOF" command after the "pause" command; otherwise, after press a key the program continue with the code of the subroutine with no parameter. This, of course, produce "missing operator" error.

This is the corrected code:

Code: Select all

@echo on
setlocal EnableDelayedExpansion

set file="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"

for %%F in (%file%) do set "filesize=%%~zF"
for /F "tokens=3" %%F in ('dir /-C "%~N0.bat"') do set "availableSpace=%%F"

call :DecimalToPowerOf1024 %filesize% %file%
call :DecimalToPowerOf1024 %availableSpace% %drive%

rem Test if availableSpace in drive is greater than filesize:

rem If there are more groups of numbers in drive than in file
if %drive% gtr %file% goto enoughSpace

rem If there are the same groups of numbers and drive number is greater than file number
if %drive% equ %file% if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace

echo Not enough space
pause
goto :EOF

:enoughSpace
echo Enough space: proceed to copy
pause
goto :EOF


:DecimalToPowerOf1024

rem DecimalToPowerOf1024.bat bigNumber [arrayName]
rem Decimal to power-of-1024 base conversion of an unlimited size decimal number
rem Antonio Perez Ayala

rem Get the name of the array, if any
set power=PowerOf1024
if "%~2" neq "" set "power=%~2"

rem Divide the number in 9-digits groups, eliminating left zeros in each group
set number=%1
set groups=0
:nextGroup
   set group=%number:~-9%
   for /L %%a in (1,1,8) do if "!group:~0,1!" equ "0" set group=!group:~1!
   set /A groups+=1
   set group[%groups%]=%group%
   set number=%number:~0,-9%
if defined number goto nextGroup

rem Convert the 9-digits groups to power-of-1024 values
set /A bitPos=0, %power%=0, %power%[0]=0
:nextBinaryDigit
   rem Divide the 9-digits groups by 2
   set carry=0
   for /L %%i in (%groups%,-1,1) do (
      set /A term=carry*1000000000+group[%%i], group[%%i]=term/2, carry=term%%2
   )
   rem Insert remainder in current PowerOf1024 value, in right-to-left order
   set /A "%power%[!%power%!]+=carry<<bitPos, bitPos+=1"
   rem If current PowerOf1024 value completed: pass to next one
   if %bitPos% equ 10 set /A bitPos=0, %power%+=1 & set %power%[!%power%!]=0
   rem If last (most significant) group was completely converted: eliminate it
   if !group[%groups%]! equ 0 set /A groups-=1
   rem And pass to convert the rest of 9-digits groups
if %groups% gtr 0 goto nextBinaryDigit
for %%p in (!%power%!) do if !%power%[%%p]! equ 0 set "%power%[%%p]=" & set /A %power%-=1

exit /B


Antonio

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#12 Post by julesverne » 13 Jan 2014 21:55

Thanks for the suggestions all! I was about to start down that road until @Aacini helped. Thanks @Aacini

So I've been working on correcting that code that I posted all day long. I've gotten pretty good at deciphering bat files but your code was definitely a difficult nut for me to crack. I was getting close to figuring it out (including all the bugs you mentioned save 1 -
The main program requires a "setlocal EnableDelayedExpansion" command, because it execute: "if !drive[%drive%]! gtr !file[%file%]! goto enoughSpace".
). And I just changed that as well... so I think at some point I may have gotten it, I at least would've been pining over it for awhile.

Anyway, I really appreciate your help with the code. Not the first time you've helped me. I just tested it out and works perfect. Thanks again!

foxidrive
Expert
Posts: 6031
Joined: 10 Feb 2012 02:20

Re: Help with File Size Calculations

#13 Post by foxidrive » 14 Jan 2014 01:29

julesverne wrote:Hi Foxidrive, thanks! Unfortunately, the reason this won't work for me is the Windows 32 bit size limit.


Did you test it? I think you will find that it doesn't have a 32 bit limit and is byte accurate.

julesverne
Posts: 81
Joined: 19 Nov 2013 00:41

Re: Help with File Size Calculations

#14 Post by julesverne » 14 Jan 2014 10:20

@foxidrive

julesverne wrote:
Hi Foxidrive, thanks! Unfortunately, the reason this won't work for me is the Windows 32 bit size limit.


Did you test it? I think you will find that it doesn't have a 32 bit limit and is byte accurate.


I did test it, only a couple times. Admittedly I didn't try hard enough to fix the problem that I realized, I was creating for myself. It works great! and real short code. I LOVE IT!!

Despite my issues with getting all this working... All the debugging I did yesterday and just now definitely widened my knowledge of working in bat and hopefully in the future this will help me help others.

Thanks for your help @foxidrive

Aacini
Expert
Posts: 1914
Joined: 06 Dec 2011 22:15
Location: México City, México
Contact:

Re: Help with File Size Calculations

#15 Post by Aacini » 14 Jan 2014 10:39

foxidrive wrote:
julesverne wrote:Hi Foxidrive, thanks! Unfortunately, the reason this won't work for me is the Windows 32 bit size limit.


Did you test it? I think you will find that it doesn't have a 32 bit limit and is byte accurate.


You are right in the sense that VBS/JScript numbers are not limited to 32 bits, so this may be used in simpler solutions. For example, this one uses JScript:

Code: Select all

@echo off
set file="C:\Users\xxx\Videos\movie\VIDEO_TS\all.vob"
for %%F in (%file%) do set "filesize=%%~zF"
for /F "tokens=3" %%F in ('dir /-C "%~N0.bat"') do set "availableSpace=%%F"
>"%temp%\geq.js" echo WScript.Quit(%availableSpace%^>=%filesize%?0:1)
cscript //nologo "%temp%\geq.js"
if %errorlevel% equ 0 (
   echo Enough space: proceed to copy
) else (
   echo Not enough space
)
del "%temp%\geq.js"
pause


However, this does NOT means that VBS/JScript method can correctly process big numbers like the one posted at beginning of this thread (comprised of 30 digits). I searched the web looking for the number of significant digits that VBS/JScript may process and found nothing, so I did a test. I modified your code this way:

Code: Select all

@echo off
set calc=%1-%2
echo %calc%
>"%temp%\VBS.vbs" echo if (%calc%) ^> -1 then wscript.echo "yes" else wscript.echo "no"
for /f "delims=" %%a in ('cscript /nologo "%temp%\VBS.vbs"') do set "result=%%a"
del "%temp%\VBS.vbs"
echo %result%

... called it geq.bat and tested on numbers every time larger. The result was wrong when the numbers have just 17 digits...

Code: Select all

C:\> geq 1234 1235
1234-1235
no

C:\> geq 1234 1233
1234-1233
yes

C:\> geq 1234567890123456 1234567890123459
1234567890123456-1234567890123459
no

C:\> geq 12345678901234567 12345678901234569
12345678901234567-12345678901234569
yes


Antonio

Post Reply