Dealing with VERY large numbers
BlitzPlus Forums/BlitzPlus Programming/Dealing with VERY large numbers
| ||
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. |
| ||
display them in kilobytes, or even megs?> |
| ||
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. |
| ||
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 |
| ||
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. |
| ||
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. |
| ||
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. |
| ||
Oh, duh, the GetFileSize function in kernel32 already splits it up for you... just need a simple .decls |
| ||
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 |
| ||
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 |
| ||
timjo, did you try this? |
| ||
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. |
| ||
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. |