October 30, 2025, 06:04:49 PM

News:

IWBasic runs in Windows 11!


Determining File Size

Started by billhsln, December 25, 2010, 02:39:13 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

billhsln

I am trying to get the correct file size of entire directories, however the results I am getting don't make any sense.

Here is a stripped down copy of my code.

$MAIN
AUTODEFINE "off"

DEF run, cd, i, j, k:INT
DEF handle[30]:UINT
DEF dSize[30]:UINT64
DEF dir[260]:ISTRING

TYPE filetime
DEF qwtime:UINT64
ENDTYPE

TYPE WIN32_FIND_DATA
DEF dwFileAttributes AS INT
DEF ftCreationTime AS FILETIME
DEF ftLastAccessTime AS FILETIME
DEF ftLastWriteTime AS FILETIME
DEF nFileSizeHigh AS UINT
DEF nFileSizeLow AS UINT
DEF dwReserved0 AS INT
DEF dwReserved1 AS INT
DEF cFileName[MAX_PATH] AS ISTRING
DEF cAlternate[14] AS ISTRING
ENDTYPE

FOR i = 0 TO 29
handle[i] = 0
dsize[i] = 0
NEXT i

OPENCONSOLE

dir = "C:\\Users\\BillH\\Movies\\VIDEO_TS\\"
cd = 0
GetFiles(dir)
PRINT "Press Enter to End"
INPUT k
CLOSECONSOLE
END

SUB GetFiles(path:STRING)
DEF dir, attrib:INT
DEF filename = "":STRING
DEF tSize = 0, Size = 0:UINT64

dir = FINDOPEN(path + "*.*")
IF (dir)
DO
filename = FINDNEXT(dir,attrib)
IF len(filename)
IF (attrib & @file_directory)
IF (filename = ".") OR (filename = "..")
filename = "x"
ELSE
cd++
dsize[cd] = 0
GetFiles(path + filename + "\\")
ENDIF
ELSE
' Size = *<WIN32_FIND_DATA>dir.nFileSizeLow + 256q * *<WIN32_FIND_DATA>dir.nFileSizeHigh
Size = ((*<WIN32_FIND_DATA>dir.nFileSizeHigh << 32) | *<WIN32_FIND_DATA>dir.nFileSizeLow)
PRINT filename," ",USING("%q###,###,###,###,###",Size)
tSize += Size
ENDIF
ENDIF
UNTIL filename = ""
FINDCLOSE dir
ENDIF
dsize[cd] += tSize
PRINT path," ",USING("%q###,###,###,###,###",dsize[cd])," ",cd
cd--
dsize[cd] += tSize
RETURN
ENDSUB


The results this prints is:

QuoteVIDEO_TS.BUP            8,192
VIDEO_TS.IFO           73,728
VTS_01_0.BUP           73,728
VTS_01_0.IFO      1,072,801,792
VTS_01_1.VOB      1,072,875,520
VTS_01_2.VOB       214,685,696
VTS_01_3.VOB       214,685,696
C:\Users\BillH\Movies\VIDEO_TS\      2,575,204,352 0
Press Enter to End

But when I do a standard DIR from DOS Window, I get:

QuoteDirectory of C:\Users\BillH\Movies\VIDEO_TS

12/23/2010  05:35 PM    <DIR>          .
12/23/2010  05:35 PM    <DIR>          ..
12/23/2010  05:35 PM             8,192 VIDEO_TS.BUP
12/23/2010  05:35 PM             8,192 VIDEO_TS.IFO
12/23/2010  05:35 PM            73,728 VTS_01_0.BUP
12/23/2010  05:35 PM            73,728 VTS_01_0.IFO
12/23/2010  05:24 PM     1,072,801,792 VTS_01_1.VOB
12/23/2010  05:34 PM     1,072,875,520 VTS_01_2.VOB
12/23/2010  05:35 PM       214,685,696 VTS_01_3.VOB
               7 File(s)  2,360,526,848 bytes

The File sizes do not match.  Maybe some one else could take a look at what I am doing and maybe see what I messed up.

Thanks,
Bill
When all else fails, get a bigger hammer.

sapero

December 25, 2010, 03:17:07 AM #1 Last Edit: December 25, 2010, 03:19:40 AM by sapero
Hi billhsln, the problem lies at the alignment of your filetime structure. It can't be defined as int64 here, because int64 in structures will be automatically aligned to 8 byte boundary. You can replace int64 with two integers, or force 4 byte alignment in the finddata structure:TYPE WIN32_FIND_DATA,4Or just include windowssdk.inc :)

billhsln

Changed:

TYPE filetime
   DEF dwLowDateTime:INT
   DEF dwHighDateTime:INT
ENDTYPE

first and then after that did not fix the problem, then tried:

TYPE WIN32_FIND_DATA,4

still returns the same bad results.

Thanks,
Bill
When all else fails, get a bigger hammer.

sapero

Got it, it seems to be invalid use of my previous "trick":
SUB GetFiles(path:STRING)
DEF dir:INT
DEF tSize = 0, Size = 0:UINT64

dir = FINDOPEN(path + "*.*")
while (dir)

IF (*<WIN32_FIND_DATA>dir.dwFileAttributes & @FILE_DIRECTORY)
IF (*<WIN32_FIND_DATA>dir.cFileName = ".") OR (*<WIN32_FIND_DATA>dir.cFileName = "..")
'filename = "x"
ELSE
cd++
dSize[cd] = 0
GetFiles(path + *<WIN32_FIND_DATA>dir.cFileName + "\\")
ENDIF
ELSE
Size = *<WIN32_FIND_DATA>dir.nFileSizeLow + (4294967296q * *<WIN32_FIND_DATA>dir.nFileSizeHigh)
PRINT *<WIN32_FIND_DATA>dir.cFileName," ",USING("%q###,###,###,###,###",Size)
tSize += Size
ENDIF

istring temp[MAX_PATH] = FINDNEXT(dir)
if (!*<WIN32_FIND_DATA>dir.cFileName[0])
FINDCLOSE(dir)
dir = 0
endif
ENDWHILE
dSize[cd] += tSize
PRINT path," ",USING("%q###,###,###,###,###",dSize[cd])," ",cd
cd--
dSize[cd] += tSize
RETURN
ENDSUB

billhsln

The file size is not exactly 100% of the problem.

Both VIDEO_TS.BUP  and VIDEO_TS.IFO should be  8,192, which is the correct size for both.

My problem is that the file size does not match the file.

Bill
When all else fails, get a bigger hammer.

sapero

The construction of your loop was wrong, because FINDOPEN actually returns initialized WIN32_FIND_DATA for the first file, and after you entered do-while loop and called FINDNEXT, the file name returned from FINDNEXT did not matched the properties in WIN32_FIND_DATA, which was already initialized for the next file. If you want to cast dir variable to WIN32_FIND_DATA, you must follow the rules from my example code, and ignore the string and attributes from FINDNEXT. FINDOPEN calls FindFirstFile, copies file name and its attributes to a buffer, so they can be returned in the next call to FINDNEXT. FINDNEXT calls FindNextFile, returns the previously saved file nams and attributes, then copies new file name to buffer.

dir = FINDOPEN
  dir = WIN32_FIND_DATA with first file.
name = FINDNEXT
  name = first file.
  dir = WIN32_FIND_DATA with the second file.

LarryMc

Bill,
I substituted Sapero's GetFiles routine above for yours and it works like it is suppose to.

LarryMc
LarryMc
Larry McCaughn :)
Author of IWB+, Custom Button Designer library, Custom Chart Designer library, Snippet Manager, IWGrid control library, LM_Image control library

billhsln

Thanks, Sapero and Larry.  I am now using Sapero's code and it working perfectly.  Seems it is a correct understanding of how the FINDOPEN/FINDNEXT works.  Thanks for all your help.

Will upload the final product, when I get it done.

I know there is a Utility (DirSize 32), which does exactly what I am trying to do, but I want to learn how to use TreeView controls.

Thanks again,
Bill
When all else fails, get a bigger hammer.