Dealing with VERY large numbers

BlitzPlus Forums/BlitzPlus Programming/Dealing with VERY large numbers

Timjo(Posted 2008) [#1]
I'm trying to create an application to find the sizes of various files/folders to display a pie chart showing a percentage of space that each file/folder is using. The problem is that when adding up file sizes (especially large video files) the byte sizes can go out of the range of BlitzPlus integers. Does anyone have a way around this problem? I'm sure there is another way of handling this. Thanks.


Snarkbait(Posted 2008) [#2]
display them in kilobytes, or even megs?>


Timjo(Posted 2008) [#3]
Yeah, I'd thought of that - except that when using the FILESIZE command you get a value returned and assigned to your variable that is in bytes. If this value goes above the limit (2147483647 according to the docs) then things get messed up. Does anyone have a way around this? I keep getting negative values for file sizes out of this acceptable range.


Dreamora(Posted 2008) [#4]
thats because int is signed but the filesize is unsigned int
what you need to do is divide it by 1024 and then recalculate its "real" value so it will be back in the positive. (this means divide the maximum neg number by 1024 as well as add the difference to that to the maximum positive number / 1024


Floyd(Posted 2008) [#5]
Provided you use a number which is a power of 2 ( such a 1024 = 2^10 ) you can fake integer division with a shift.

Thus ( size Shr 10 ) is the size divided by 1024. And Shr doesn't care if size is positive or negative.


sswift(Posted 2008) [#6]
Um, you can have files which are larger than 4gb, so even if he solves the negative int issue, he still can't get proper file sizes for really large files.


Snarkbait(Posted 2008) [#7]
Well then you'd have to use a dll, use 64-bit ints in c++ or the like, then have it send the file size already converted down to blitz.


Snarkbait(Posted 2008) [#8]
Oh, duh, the GetFileSize function in kernel32 already splits it up for you... just need a simple .decls


Snarkbait(Posted 2008) [#9]
Ok, here you go, however, I don't have any files big enough to test it.

.decls file, put in /userlibs folder or add to existing kernel32.decls

.lib "kernel32.dll"

api_CreateFile%(FileName$, dwDesiredAccess%, dwShareMode%, lpSecurity%, dwCreationDsp%, dwFlagsAndAttr%, hTemplate%):"CreateFileA"

api_GetFileSize% ( hFile%, lpFileSizeHigh*) : "GetFileSize"


and test code:
; CreateFile:Desired Access
Const GENERIC_WRITE = $40000000
Const GENERIC_READ = $80000000
; CreateFile:FlagsAndAttributes
Const FILE_ATTRIBUTE_NORMAL = $80
; CreateFile:CreationDisposition
Const OPEN_EXISTING = 3
; CreateFile:ShareMode
Const FILE_SHARE_READ = 1
Const FILE_SHARE_WRITE = 2

filename$ = RequestFile()

; get api file handle
hFile = api_CreateFile( filename$, GENERIC_WRITE Or GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
If hFile > 0

	hiBank = CreateBank(8)
	
	
	lowDword = api_GetFileSize( hFile, hiBank)
	
	highDword = PeekInt(hiBank,0)
	
	
	Print lowDword
	Print highDword
	
	api_CloseHandle( hFile )
	
EndIf 

WaitKey
End



Snarkbait(Posted 2008) [#10]
Nobody cares, but I tweaked the above code further.

Added error trapping, types and & a function.

added 1 line to decls file:
.lib "kernel32.dll"

api_CreateFile%(FileName$, dwDesiredAccess%, dwShareMode%, lpSecurity%, dwCreationDsp%, dwFlagsAndAttr%, hTemplate%):"CreateFileA"

api_GetFileSize% ( hFile%, lpFileSizeHigh*) : "GetFileSize"
api_GetLastError%() : "GetLastError"


and the include file
; GetFileSize.bb include file
; snarkbait66 @ gmail.com

; CreateFile:Desired Access
Const GENERIC_WRITE = $40000000
Const GENERIC_READ = $80000000
; CreateFile:FlagsAndAttributes
Const FILE_ATTRIBUTE_NORMAL = $80
; CreateFile:CreationDisposition
Const OPEN_EXISTING = 3
; CreateFile:ShareMode
Const FILE_SHARE_READ = 1
Const FILE_SHARE_WRITE = 2

; const for file size error
INVALID_FILE_SIZE = $FFFFFFFF

Type dWord
	Field lowWord
	Field highWord
End Type

Function GetFileSize.dword( filename$ )

	; get API filehandle
	hFile = api_CreateFile( filename$, GENERIC_WRITE Or GENERIC_READ, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)

	; if file handle is valid
	If hFile > 0
		
		; instantiate object
		this.dWord = New dWord
		
		; create bank for pointer
		hiBank = CreateBank(8)
		
		; call api GetFileSize command, if
		this\lowWord = api_GetFileSize( hFile, hiBank)
		
		; get high part of dWord from pointer
		; if = 0 then filesize = lowWord
		this\highWord = PeekInt(hiBank,0)
		
		; trap error - if there is an error, lowWord
		; will be = $FFFFFFFF
		; on extremely off-chance that actual filesize
		; is that, check 'GetLastError' for 0
		If this\lowWord  = INVALID_FILE_SIZE
			If api_GetLastError() <> 0
				Return Null
			EndIf
		EndIf
		
		; close file handle
		api_CloseHandle( hFile )
		
		Return this
	
	Else
		;unable to create file handle
		Return Null	
	EndIf 
End Function 


and test code:
Include "GetFileSize.bb"

filename$ = RequestFile()

test.dWord = GetFileSize( filename$ )

If test = Null
	Print "Error."
Else
	Print test\lowWord
	Print test\highWord
EndIf


WaitKey 
End




Snarkbait(Posted 2008) [#11]
timjo, did you try this?


Timjo(Posted 2008) [#12]
Thanks for all the effort, Snarkbait. It's much appreciated. I'm going to have to work my way through it all to make sure I know what's going on. Also have to familiarise myself with the userlibs stuff - never used it before so not too sure what to do yet - I'll find some info in the forums I'm sure. Thanks.


Snarkbait(Posted 2008) [#13]
Copy the code from the first code box, into a blank text doc in notepad, and save as "kernel32.decls" into your "blitzplus/userlibs/" folder. restart the blitz IDE. Now the commands in that userlib will be syntax highlighted and should work properly.


Now, as to the math to consolidate the two values, I'm not sure at all.