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
ENDSUBThe 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
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 :)
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
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
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
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.
Bill,
I substituted Sapero's GetFiles routine above for yours and it works like it is suppose to.
LarryMc
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