Parse DIR listing for folder name and size
Parse DIR listing for folder name and size
I am having a hell of a time trying to parse a directory listing to get just the folder name, and folder size.
I just want to retrieve the following including total files and bytes. I know there are many FreeBasic gurus out there, and probably an easy solution to this problem, but I am at a loss.
Folder 1, 540235493 bytes
Folder 2, 256470327 bytes
Folder 3, 1430815946 bytes
Folder 4, 1496155138 bytes
Folder 5, 1382708779 bytes
11 File, 5106385683 bytes
For example, below is a DIR listing (DIR /S /-C):
Volume in drive G is 1.5Terrabyte
Volume Serial Number is 5492-5AFI
Directory of G:\test
06/08/2020 10:42 AM <DIR> .
06/08/2020 10:42 AM <DIR> ..
06/08/2020 12:40 PM <DIR> Folder 1
06/08/2020 10:40 AM <DIR> Folder 2
06/08/2020 10:40 AM <DIR> Folder 3
06/08/2020 12:41 PM <DIR> Folder 4
06/08/2020 12:41 PM <DIR> Folder 5
0 File(s) 0 bytes
Directory of G:\test\Folder 1
06/08/2020 12:40 PM <DIR> .
06/08/2020 12:40 PM <DIR> ..
08/24/2019 08:08 AM 108167 backup_1.tib
08/24/2019 08:52 AM 533477418 backup_2.tib
08/24/2019 08:08 AM 6649856 backup_3.tib
08/24/2019 06:57 AM 52 text.txt
4 File(s) 540235493 bytes
Directory of G:\test\JFolder 2
06/08/2020 10:40 AM <DIR> .
06/08/2020 10:40 AM <DIR> ..
06/06/2020 12:40 PM 256379805 Backup_4.tib
12/16/2018 07:05 PM 90522 Backup_5.tib
2 File(s) 256470327 bytes
Directory of G:\test\Folder 3
06/08/2020 10:40 AM <DIR> .
06/08/2020 10:40 AM <DIR> ..
08/09/2019 09:24 PM 1430815946 Backup_6.tib
1 File(s) 1430815946 bytes
Directory of G:\test\Folder 4
06/08/2020 12:41 PM <DIR> .
06/08/2020 12:41 PM <DIR> ..
08/09/2019 09:02 PM 1496154228 Backup_7.tib
08/10/2019 10:56 AM 910 text.txt
2 File(s) 1496155138 bytes
Directory of G:\test\Folder 5
06/08/2020 12:41 PM <DIR> .
06/08/2020 12:41 PM <DIR> ..
08/11/2019 11:28 AM 1382707834 Backup_8.tib
08/11/2019 11:30 AM 945 text.txt
2 File(s) 1382708779 bytes
Total Files Listed:
11 File(s) 5106385683 bytes
17 Dir(s) 714031509504 bytes free
Information is GREATLY Appreciated!
Nick
I just want to retrieve the following including total files and bytes. I know there are many FreeBasic gurus out there, and probably an easy solution to this problem, but I am at a loss.
Folder 1, 540235493 bytes
Folder 2, 256470327 bytes
Folder 3, 1430815946 bytes
Folder 4, 1496155138 bytes
Folder 5, 1382708779 bytes
11 File, 5106385683 bytes
For example, below is a DIR listing (DIR /S /-C):
Volume in drive G is 1.5Terrabyte
Volume Serial Number is 5492-5AFI
Directory of G:\test
06/08/2020 10:42 AM <DIR> .
06/08/2020 10:42 AM <DIR> ..
06/08/2020 12:40 PM <DIR> Folder 1
06/08/2020 10:40 AM <DIR> Folder 2
06/08/2020 10:40 AM <DIR> Folder 3
06/08/2020 12:41 PM <DIR> Folder 4
06/08/2020 12:41 PM <DIR> Folder 5
0 File(s) 0 bytes
Directory of G:\test\Folder 1
06/08/2020 12:40 PM <DIR> .
06/08/2020 12:40 PM <DIR> ..
08/24/2019 08:08 AM 108167 backup_1.tib
08/24/2019 08:52 AM 533477418 backup_2.tib
08/24/2019 08:08 AM 6649856 backup_3.tib
08/24/2019 06:57 AM 52 text.txt
4 File(s) 540235493 bytes
Directory of G:\test\JFolder 2
06/08/2020 10:40 AM <DIR> .
06/08/2020 10:40 AM <DIR> ..
06/06/2020 12:40 PM 256379805 Backup_4.tib
12/16/2018 07:05 PM 90522 Backup_5.tib
2 File(s) 256470327 bytes
Directory of G:\test\Folder 3
06/08/2020 10:40 AM <DIR> .
06/08/2020 10:40 AM <DIR> ..
08/09/2019 09:24 PM 1430815946 Backup_6.tib
1 File(s) 1430815946 bytes
Directory of G:\test\Folder 4
06/08/2020 12:41 PM <DIR> .
06/08/2020 12:41 PM <DIR> ..
08/09/2019 09:02 PM 1496154228 Backup_7.tib
08/10/2019 10:56 AM 910 text.txt
2 File(s) 1496155138 bytes
Directory of G:\test\Folder 5
06/08/2020 12:41 PM <DIR> .
06/08/2020 12:41 PM <DIR> ..
08/11/2019 11:28 AM 1382707834 Backup_8.tib
08/11/2019 11:30 AM 945 text.txt
2 File(s) 1382708779 bytes
Total Files Listed:
11 File(s) 5106385683 bytes
17 Dir(s) 714031509504 bytes free
Information is GREATLY Appreciated!
Nick
-
- Posts: 2958
- Joined: Jun 02, 2015 16:24
Re: Parse DIR listing for folder name and size
Hello,nfunk wrote:I am having a hell of a time trying to parse a directory listing to get just the folder name, and folder size.
as far as I remember this is not that trivial to get those kind of metrics (directory tend to have a lot of subdirectories in there). Even powershell which is the job can be slow on that (from my remembrance).
Maybe you could use a simple utility program like microsoft Diskusage?
https://docs.microsoft.com/en-us/sysint ... k-usage-du
If you use Shell in FB, maybe you'll have to take care of well enclosing things within quotes. Otherwise it will be easy to output at the console, or to create a CSV with your statistics.
Code: Select all
var d = """"& curDir() &""""
shell("du64.exe -nobanner -v " & d )
Re: Parse DIR listing for folder name and size
If you do it in freebasic, a recursive function is needed.
Also there is 'useful' file size and the disc size used (also for directories).
Here on linux, I can say du -s --apparent-size Pictures/ and du -s Pictures/
Also there is 'useful' file size and the disc size used (also for directories).
Here on linux, I can say du -s --apparent-size Pictures/ and du -s Pictures/
Last edited by badidea on Jun 21, 2020 20:28, edited 2 times in total.
Re: Parse DIR listing for folder name and size
NOT very trivial, but not too difficult.
This works here.
WINDOWS ONLY (due to crt stats)
my results
This works here.
WINDOWS ONLY (due to crt stats)
Code: Select all
#include "crt.bi"
#include "file.bi"
Declare Function stats Cdecl Alias "_stat"(As zstring Ptr,As Any Ptr) As Integer
Function String_Split(s_in As String,chars As String,result() As String) As Long
Dim As Long ctr,ctr2,k,n,LC=Len(chars)
Dim As boolean tally(Len(s_in))
#macro check_instring()
n=0
While n<Lc
If chars[n]=s_in[k] Then
tally(k)=true
If (ctr2-1) Then ctr+=1
ctr2=0
Exit While
End If
n+=1
Wend
#endmacro
#macro split()
If tally(k) Then
If (ctr2-1) Then ctr+=1:result(ctr)=Mid(s_in,k+2-ctr2,ctr2-1)
ctr2=0
End If
#endmacro
'================== LOOP TWICE =======================
For k =0 To Len(s_in)-1
ctr2+=1:check_instring()
Next k
if ctr=0 then
if len(s_in) andalso instr(chars,chr(s_in[0])) then ctr=1':beep
end if
If ctr Then Redim result(1 To ctr): ctr=0:ctr2=0 Else Return 0
For k =0 To Len(s_in)-1
ctr2+=1:split()
Next k
'===================== Last one ========================
If ctr2>0 Then
Redim Preserve result(1 To ctr+1)
result(ctr+1)=Mid(s_in,k+1-ctr2,ctr2)
End If
Return Ubound(result)
End Function
Function _Remove(Byval Text As String,Char As String) As String
Var index = 0,asci=Asc(char)
For i As Integer = 0 To Len(Text) - 1
If Text[i] <> ASCi Then Text[index] = Text[i] : index =index+ 1
Next
Return Left(Text,index)
End Function
Function isfolder(path As zstring Ptr) As Long
#define S_ISDIR(m) (((m) And &hF000) = &h4000)
Dim As stat statbuf
If (stats(path, @statbuf) <> 0) Then Return 0
Return S_ISDIR(statbuf.st_mode)
End Function
Function isfile(fname As String) As boolean
'return fileexists(fname)
Return Iif(isfolder(fname),0,1)
End Function
Function pipeout(Byval s As String="") Byref As String
Var f=Freefile
Dim As String tmp
Open Pipe s For Input As #f
s=""
Do Until Eof(f)
Line Input #f,tmp
s+=tmp+Chr(10)
Loop
Close #f
Return s
End Function
dim shared as ulongint sz
function Size(inputs As String) as long
dim as string path
If isfile(inputs) Then return filelen(inputs)
Dim As String file
If Instr(inputs," ") Then inputs=Chr(34)+inputs+Chr(34)
Dim As String s=pipeout("dir /b " + inputs)
reDim As String a()
string_split(s,Chr(13,10),a())
inputs=_remove(inputs,Chr(34))
For n As Long=Lbound(a) To Ubound(a)
path=(inputs+"\"+a(n))
If isfile(path) Then
Redim As String tmp()
string_split(path,"\",tmp())
file= tmp(Ubound(tmp))
If Instr(file," ") Then file=Chr(34)+file+Chr(34)
sz+=filelen(path)
Else
size(path) 'for nested folders
End If
Next n
return sz
End function
sub show(fullpath as string)
if instr(fullpath," ") then fullpath=chr(34)+fullpath+chr(34)
dim as string g=pipeout( "dir "+fullpath)
var i=instr(g,":")-1
var i1=instr(mid(g,i),chr(10))-1
dim as string fpath=mid(g,i,i1)+"\"
print fpath
dim as const string dirlist="dir /b "
dim as string path=dirlist+ fullpath
var s=pipeout(path)
redim as string a()
string_split(s,chr(10),a())
for n as long=lbound(a) to ubound(a)
sz=0
print mid(a(n),instrrev(a(n),"\")+1);tab(40);size(fpath+ a(n));tab(60); iif(isfolder(fpath+ a(n)),"--->folder","")
next
end sub
dim as string fullpath="C:\Users\User\Desktop\Return to Castle Wolfenstein"
show(fullpath)
print"DONE . . ."
sleep
Code: Select all
C:\Users\User\Desktop\Return to Castle Wolfenstein\
anet.inf 345
BACKUP 0 --->folder
cgamex86.dll 536576
cgame_mp_x86.dll 573440
Docs 1053315 --->folder
Getinfo.dll 23552
gl 630784 --->folder
Main 702482252 --->folder
qagamex86.dll 708608
qagame_mp_x86.dll 753664
register.exe 131072
servercache.dat 350224
sysinfo.exe 84480
Sysinv.dll 38912
uix86.dll 225280
ui_mp_x86.dll 217088
Uninstall 196778 --->folder
WolfMP.exe 1024057
WolfSP.exe 1282095
Re: Parse DIR listing for folder name and size
The dir command cannot be used recursively that simple it seems:
So first a list of directories need to be made before visiting that directory and complete looping the current directory first. To be continued...
This seems to work better. But ends up in a loop when encountering directory links.
So next step: Add this: How do I detect if a file is symbolic link?
Tomorrow...
Code: Select all
#include "dir.bi"
#include "file.bi"
const as integer ATTR_MASK_ALL = _
fbArchive or fbNormal or fbHidden or fbSystem or fbDirectory
const as integer KB = 1024, MB = 1024 * 1024, GB = 1024 * 1024 * 1024
type file_info
dim as ulongint apparentSize
dim as uLong fileCount
dim as uLong dirCount
end type
'get size and count of file or directory
function getFileInfo(fileSpec as string) as file_info
dim as file_info retInfo, tempInfo
dim as integer outAttr
dim as string fileName = dir(filespec, ATTR_MASK_ALL, outAttr)
while len(filename) > 0
if (fileName <> ".") and (fileName <> "..") then
if (outAttr and fbDirectory) <> 0 then
'is dir
print "DIR: " & fileName
retInfo.dirCount += 1
tempInfo = getFileInfo(fileName & "/*") '<- recursive call
retInfo.dirCount += tempInfo.dirCount
retInfo.fileCount += tempInfo.fileCount
retInfo.apparentSize += tempInfo.apparentSize
else
'is file
print "FILE: " & fileName
retInfo.fileCount += 1
retInfo.apparentSize += fileLen(fileName)
end if
end if
fileName = dir(outAttr)
wend
return retInfo
end function
dim as file_info fileInfo
fileInfo = getFileInfo("*")
print "dirCount : " & fileInfo.dirCount
print "fileCount: " & fileInfo.fileCount
print "apparent size: " & fileInfo.apparentSize & " B"
print "apparent size: " & fileInfo.apparentSize \ KB & " KB"
print "apparent size: " & fileInfo.apparentSize \ MB & " MB"
This seems to work better. But ends up in a loop when encountering directory links.
Code: Select all
type string_list
dim as string list(any)
declare function size() as integer
declare function empty() as integer
declare function add(text as string) as integer
end type
function string_list.size() as integer
return ubound(list) + 1
end function
function string_list.empty() as integer
erase(list)
return 0
end function
function string_list.add(text as string) as integer
dim as integer ub = ubound(list)
redim preserve list(ub + 1)
list(ub + 1) = text
return ub + 1
end function
#include "dir.bi"
#include "file.bi"
const as integer ATTR_MASK_ALL = _
fbArchive or fbNormal or fbHidden or fbSystem or fbDirectory
const as integer KB = 1024, MB = 1024 * 1024, GB = 1024 * 1024 * 1024
type file_info
dim as ulongint apparentSize
dim as uLong fileCount
dim as uLong dirCount
end type
'get size and count of file or directory
function getFileInfo(path as string, files as string) as file_info
static as integer depth = 0 '<- not essential, for printing
depth += 1
print string(depth, "*") & " PATH: " & path
dim as file_info retInfo, tempInfo
dim as integer outAttr
dim as string_list dirList
dim as string filespec = path & files
dim as string fileName = dir(filespec, ATTR_MASK_ALL, outAttr)
while len(filename) > 0
if (fileName <> ".") and (fileName <> "..") then
if (outAttr and fbDirectory) <> 0 then
'is dir
'print string(depth, "*") & " DIR: " & fileName
retInfo.dirCount += 1
dirList.add(fileName)
else
'is file
'print string(depth, "*") & " FILE: " & fileName, fileLen(path & fileName)
retInfo.fileCount += 1
retInfo.apparentSize += fileLen(path & fileName)
end if
end if
fileName = dir(outAttr)
wend
'loop dirs
for i as integer = 0 to dirList.size() - 1
fileName = dirList.list(i)
'print string(depth, "*") & " DIR: " & fileName
tempInfo = getFileInfo(path & fileName & "/", "*") '<- recursive call
retInfo.dirCount += tempInfo.dirCount
retInfo.fileCount += tempInfo.fileCount
retInfo.apparentSize += tempInfo.apparentSize
next
dirList.empty()
depth -= 1
return retInfo
end function
dim as file_info fileInfo
fileInfo = getFileInfo("/home/badidea/Pictures/", "*")
print "dirCount : " & fileInfo.dirCount
print "fileCount: " & fileInfo.fileCount
print "apparent size: " & fileInfo.apparentSize & " B"
print "apparent size: " & fileInfo.apparentSize \ KB & " KB"
print "apparent size: " & fileInfo.apparentSize \ MB & " MB"
print "apparent size: " & fileInfo.apparentSize \ GB & " GB"
Tomorrow...
Re: Parse DIR listing for folder name and size
I went with a fancypants thread per top-level directory approach. Don't know whether print is thread safe or not, so the mutex stuff can be removed if it is.
Code: Select all
#include "dir.bi"
#include "crt/sys/stat.bi"
Type DirInfo
Dim size As ULongInt
Dim path As String
Dim outputLock As Any Ptr
End Type
const FILE_MASK As Long = fbArchive or fbNormal or fbHidden or fbSystem
Sub DirForEach( _
ByVal path As String, _
ByVal attrib As Long, _
ByVal context As Any Ptr, _
ByVal callback As Function (ByVal wholeFileName As String, Byval context As Any Ptr) As Long _
)
Dim pathSlashed As String = path & "/"
Dim pathPattern As String = pathSlashed & "*"
Dim emptyString As String
Dim foundItem As String = Dir(pathPattern, attrib)
While foundItem <> emptyString
If foundItem <> "." And foundItem <> ".." Then
If callback(pathSlashed + foundItem, context) = False Then
Exit While
End If
End If
foundItem = Dir(emptyString, attrib)
Wend
End Sub
Function SumFileSizes(ByVal fileName As String, ByVal context As Any Ptr) As Long
Dim fData As _stat
Dim pCumulativeSize As ULongInt Ptr = context
stat(StrPtr(fileName), @fData)
*pCumulativeSize += fData.st_size
Return True
End Function
Sub ThreadSafePrint(ByVal mtx As Any Ptr, ByVal text As String)
MutexLock(mtx)
Print text
MutexUnlock(mtx)
End Sub
Function PrintChildDirs(ByVal directory As String, context As Any Ptr) As Long
Dim thisDirSize As UlongInt
Dim dirInfo As DirInfo Ptr = context
DirForEach(directory, FILE_MASK, @thisDirSize, @SumFileSizes)
dirInfo->size += thisDirSize
DirForEach(directory, fbDirectory, context, @PrintChildDirs)
Return True
End Function
Sub ThreadStart(ByVal userData As Any Ptr)
Dim dirInfo As DirInfo Ptr = userData
PrintChildDirs(dirInfo->path, dirInfo)
ThreadSafePrint(dirInfo->outputLock, "Total size of " & dirInfo->path & " is " & dirInfo->size & " bytes")
End Sub
Dim Shared g_threads(Any, Any) As Any Ptr
Type ThreadCreateContext
Dim outputLock As Any Ptr
Dim numThreads As Long
End Type
Function CreateDirThreads(ByVal fileDir As String, ByVal context As Any Ptr) As Long
Dim pTcContext As ThreadCreateContext Ptr = context
Dim numThreads As Long = pTcContext->numThreads
Dim thisTopDir As DirInfo Ptr = New DirInfo
thisTopDir->size = 0
thisTopDir->path = fileDir
Redim Preserve g_threads(numThreads + 1, 2)
g_threads(numThreads, 0) = thisTopDir
g_threads(numThreads, 1) = ThreadCreate(@ThreadStart, thisTopDir)
pTcContext->numThreads = numThreads + 1
Return True
End Function
Sub DoTopLevelDir(path As String)
Dim outputLock As Any Ptr
Dim tcContext As ThreadCreateContext
Dim size As UlongInt
outputLock = MutexCreate()
tcContext.outputLock = outputLock
tcContext.numThreads = 0
DirForEach(path, fbDirectory, @tcContext, @CreateDirThreads)
DirForEach(path, FILE_MASK, @size, @SumFileSizes)
For i As Long = 0 To tcContext.numThreads - 1
Dim pDirInfo As DirInfo Ptr = g_threads(i, 0)
ThreadWait g_threads(i, 1)
size += pDirInfo->size
Delete pDirInfo
Next
MutexDestroy(outputLock)
Print "Total Size of all files under " & path & " is " & Str(size) & " bytes"
End Sub
Dim startDir as String = Command(1)
If startDir = "" Then
startDir = CurDir()
End If
Print "Dir-ing " & startDir
DoTopLevelDir startDir
Re: Parse DIR listing for folder name and size
@nfunk:
The file size isn't equal to the memory used on disc. In order to evaluate the HDD consumption, you've to consider the sector size. In this example a sector size of 4096 bytes is used
It generates output like
In order to evaluate your sector size use system commands. Ie. on a Debian based LINUX system execute in a terminal
Regards
[edit]
Added line:
Scnt += 1 ' assuming a directory consumes 1 sector = 4096 bytes on HDD
[/edit]
The file size isn't equal to the memory used on disc. In order to evaluate the HDD consumption, you've to consider the sector size. In this example a sector size of 4096 bytes is used
Code: Select all
#INCLUDE ONCE "dir.bi"
TYPE DirSize
AS ZSTRING PTR Mask
AS ULONGINT Fsize, Ssize
AS ULONG Dcnt, Fcnt, Sect, Scnt
DECLARE CONSTRUCTOR(BYVAL M AS ZSTRING PTR, BYVAL P AS ZSTRING PTR, BYVAL S AS ULONG = 4096)
DECLARE SUB Eval()
END TYPE
CONSTRUCTOR DirSize(BYVAL M AS ZSTRING PTR, BYVAL P AS ZSTRING PTR, BYVAL S AS ULONG = 4096)
Mask = M
Sect = S
VAR cd = CURDIR()
IF CHDIR(*P) THEN EXIT CONSTRUCTOR
Eval()
CHDIR(cd)
Ssize = Sect * Scnt
END CONSTRUCTOR
SUB DirSize.Eval()
VAR res = 0, n = DIR(*Mask, fbDirectory, @res), t = ""
Dcnt += 1
Scnt += 1 ' assuming a directory consumes 1 sector = 4096 bytes on HDD
WHILE LEN(n)
IF res = fbDirectory ANDALSO n <> "." ANDALSO n <> ".." THEN t &= n & !"\n"
n = DIR("", fbDirectory, @res)
WEND
VAR a = 1, e = a, l = LEN(t)
WHILE a < l
e = INSTR(a, t, !"\n")
n = MID(t, a, e - a)
IF 0 = CHDIR(n) THEN
'?n
Eval()
CHDIR ("..")
END IF
a = e + 1
WEND
n = DIR(*Mask)
WHILE LEN(n)
VAR fnr = FREEFILE
IF 0 = OPEN(n FOR INPUT AS fnr) THEN
VAR l = LOF(fnr)
CLOSE #fnr
Fcnt += 1
Scnt += 1 + (l - 1) \ Sect
Fsize += l
'?" ";n,l,1 + (l - 1) \ Sect
END IF
n = DIR()
WEND
END SUB
VAR t = NEW DirSize(@"*.bas", @"..", 4096)
WITH *t
?"Size: " & .Fsize & " (" & .Ssize & " = " & .Scnt & " sectors)"
?"folders: " & .Dcnt & ", files: " & .Fcnt
END WITH
DELETE t
The CTOR requiresSize: 581477 (671744 = 164 sectors)
folders: 1, files: 33
- the pattern for the file names,
- the path where the evaluation should start, and
- the optional sector size (defaults to 4096).
In order to evaluate your sector size use system commands. Ie. on a Debian based LINUX system execute in a terminal
Code: Select all
$ sudo hdparm -I /dev/sda | grep Physical
Physical Sector size: 4096 bytes
[edit]
Added line:
Scnt += 1 ' assuming a directory consumes 1 sector = 4096 bytes on HDD
[/edit]
Last edited by TJF on Jun 22, 2020 9:30, edited 1 time in total.
Re: Parse DIR listing for folder name and size
In any case in your code, the value of the pointer 'mtx' used in 'MutexLock(mtx) / MutexUnlock(mtx)' is not initialized compared to the one get from 'MutexCreate()'.adeyblue wrote:Don't know whether print is thread safe or not, so the mutex stuff can be removed if it is.
The same 'outputLock' member data name is declared in two different Types !
Perhaps define 'outputLock' once as a static member data of the 'ThreadCreateContext' Type ?
Code: Select all
.....
Type ThreadCreateContext
Static outputLock As Any Ptr
Dim numThreads As Long
End Type
Dim ThreadCreateContext.outputLock As Any Ptr
Sub ThreadStart(ByVal userData As Any Ptr)
Dim dirInfo As DirInfo Ptr = userData
PrintChildDirs(dirInfo->path, dirInfo)
ThreadSafePrint(ThreadCreateContext.outputLock, "Total size of " & dirInfo->path & " is " & dirInfo->size & " bytes")
End Sub
Dim Shared g_threads(Any, Any) As Any Ptr
.....
Last edited by fxm on Jun 22, 2020 11:55, edited 5 times in total.
Re: Parse DIR listing for folder name and size
Here a variant using the Windows API:
I hope it works properly...^^
Code: Select all
'Coded by UEZ build 2020-06-22 beta
#Include "windows.bi"
Declare Sub GetDirSize(sDir As String)
Type tFileSize
Union
As Ulongint quadpart
Type
As Uinteger LowPart, HighPart
End Type
End Union
End Type
Dim As String sDir = "c:\Temp\*" '<---- change path and don't forget * at the end!
? "Dir size", "Amount of files", "Dir root name"
? " (bytes)", "within folder"
? "----------------------------------------------------------------------"
GetDirSize(sDir)
? "Done."
Sleep
Sub GetDirSize(sDir As String)
Dim As WIN32_FIND_DATA ffd
Dim As tFileSize filesize
Dim As HANDLE hFind = INVALID_HANDLE_VALUE
Dim As String sDir2
Static As Integer level = 0, filecount = 0
Static As Ulongint DirSize = 0, totalfiles = 0, totalsize = 0, totaldirs = 0
hFind = FindFirstFile(sDir, @ffd)
If hFind = INVALID_HANDLE_VALUE Then
'? "ERROR: FindFirstFile"
Exit Sub
End If
While (FindNextFile(hFind, @ffd)) <> 0
filesize.LowPart = ffd.nFileSizeLow
filesize.HighPart = ffd.nFileSizeHigh
If level > 0 Then
DirSize += filesize.quadpart
If (ffd.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY) <> FILE_ATTRIBUTE_DIRECTORY Then filecount += 1
End If
If ffd.dwFileAttributes And FILE_ATTRIBUTE_DIRECTORY And ffd.cFileName <> ".." Then
If level = 0 Then totaldirs += 1
level += 1
sDir2 = ffd.cFileName
GetDirSize(Left(sDir, InStrRev(sDir, "\")) & ffd.cFileName & Right(sDir, Len(sDir) - InStrRev(sDir, "\") + 1))
level -= 1
If level = 0 Then
? DirSize, filecount,, sDir2
totalfiles += filecount
totalsize += DirSize
DirSize = 0 : filecount = 0
End If
End If
Wend
FindClose(hFind)
If level = 0 Then
? "======================================================================"
? "Total directories: " & totaldirs
? "Total files: " & totalfiles
? "Total file size: " & totalsize & " bytes"
End If
End Sub
Re: Parse DIR listing for folder name and size
Gurus,
Well, it looks like I have a lot to learn! What I though wouldn't be difficult isn't so (at least for me). I spent hours searching the forums including Libraries hoping that I might get an idea on programming this. I will have to sit down and study everyone's code and learn the intricacies of the algorithms.
Again, Thank y'all for the help and insight!!!!!
Nick
Well, it looks like I have a lot to learn! What I though wouldn't be difficult isn't so (at least for me). I spent hours searching the forums including Libraries hoping that I might get an idea on programming this. I will have to sit down and study everyone's code and learn the intricacies of the algorithms.
Again, Thank y'all for the help and insight!!!!!
Nick
Re: Parse DIR listing for folder name and size
My code gives the sizes (as in shell dir)
The total size is the upper if you were to right click- properties.
Also the number of folders and number of files.
A run on a freebasic distro
result:
I can do this without the c runtime by using
#define isfolder(path) fileexists(path)=0
#define isfile(path) fileexists(path)
It is slightly slower.
Tested win 32, win 64 and gas64.
The total size is the upper if you were to right click- properties.
Also the number of folders and number of files.
Code: Select all
#include "crt.bi"
#include "file.bi"
Declare Function stats Cdecl Alias "_stat"(As zstring Ptr,As Any Ptr) As Integer
Function String_Split(s_in As String,chars As String,result() As String) As Long
Dim As Long ctr,ctr2,k,n,LC=Len(chars)
Dim As boolean tally(Len(s_in))
#macro check_instring()
n=0
While n<Lc
If chars[n]=s_in[k] Then
tally(k)=true
If (ctr2-1) Then ctr+=1
ctr2=0
Exit While
End If
n+=1
Wend
#endmacro
#macro split()
If tally(k) Then
If (ctr2-1) Then ctr+=1:result(ctr)=Mid(s_in,k+2-ctr2,ctr2-1)
ctr2=0
End If
#endmacro
'================== LOOP TWICE =======================
For k =0 To Len(s_in)-1
ctr2+=1:check_instring()
Next k
If ctr=0 Then
If Len(s_in) Andalso Instr(chars,Chr(s_in[0])) Then ctr=1':beep
End If
If ctr Then Redim result(1 To ctr): ctr=0:ctr2=0 Else Return 0
For k =0 To Len(s_in)-1
ctr2+=1:split()
Next k
'===================== Last one ========================
If ctr2>0 Then
Redim Preserve result(1 To ctr+1)
result(ctr+1)=Mid(s_in,k+1-ctr2,ctr2)
End If
Return Ubound(result)
End Function
Function _Remove(Byval Text As String,Char As String) As String
Var index = 0,asci=Asc(char)
For i As Integer = 0 To Len(Text) - 1
If Text[i] <> ASCi Then Text[index] = Text[i] : index =index+ 1
Next
Return Left(Text,index)
End Function
Function isfolder(path As zstring Ptr) As Long
#define S_ISDIR(m) (((m) And &hF000) = &h4000)
Dim As stat statbuf
If (stats(path, @statbuf) <> 0) Then Return 0
Return S_ISDIR(statbuf.st_mode)
End Function
Function isfile(fname As String) As boolean
Return Iif(isfolder(fname),0,1)
End Function
Function pipeout(Byval s As String="") Byref As String
Var f=Freefile
Dim As String tmp
Open Pipe s For Input As #f
s=""
Do Until Eof(f)
Line Input #f,tmp
s+=tmp+Chr(10)
Loop
Close #f
Return s
End Function
Dim Shared As Ulongint sz,filecount,foldercount
Function Size(inputs As String) As Long
Dim As String path
If isfile(inputs) Then filecount+=1: Return Filelen(inputs)
foldercount+=1
Dim As String file
If Instr(inputs," ") Then inputs=Chr(34)+inputs+Chr(34)
Dim As String s=pipeout("dir /b " + inputs)
Redim As String a()
string_split(s,Chr(13,10),a())
inputs=_remove(inputs,Chr(34))
For n As Long=Lbound(a) To Ubound(a)
path=(inputs+"\"+a(n))
If isfile(path) Then
filecount+=1
Redim As String tmp()
string_split(path,"\",tmp())
file= tmp(Ubound(tmp))
If Instr(file," ") Then file=Chr(34)+file+Chr(34)
sz+=Filelen(path)
Else
size(path) 'for nested folders
End If
Next n
Return sz
End Function
Sub show(fullpath As String)
Print "Please wait while counting . . ."
If Instr(fullpath," ") Then fullpath=Chr(34)+fullpath+Chr(34)
Dim As String g=pipeout( "dir "+fullpath)
Var i=Instr(g,":")-1
Var i1=Instr(Mid(g,i),Chr(10))-1
Dim As String fpath=Mid(g,i,i1)+"\"
Print fpath
Dim As Const String dirlist="dir /b "
Dim As String path=dirlist+ fullpath
Var s=pipeout(path)
Redim As String a()
string_split(s,Chr(10),a())
Dim As Ulong tot,d,n
For n As Long=Lbound(a) To Ubound(a)
sz=0
d=size(fpath+ a(n))
Print Mid(a(n),Instrrev(a(n),"\")+1);Tab(40);d;Tab(55); Iif(isfolder(fpath+ a(n)),"--->folder","")
tot+=d
Next
Print Tab(35);"__________________"
Print "Total size ";Tab(40);tot
Print "Files ";filecount
Print "Folders "; foldercount
End Sub
Dim As String fullpath="C:\fb17_64\FreeBASIC-1.07.1-win64\FreeBASIC-1.07.1-win64"
show(fullpath)
Print"DONE . . ."
Sleep
result:
Code: Select all
Please wait while counting . . .
C:\fb17_64\FreeBASIC-1.07.1-win64\FreeBASIC-1.07.1-win64\
bin 27308032 --->folder
changelog.txt 261503
doc 52574 --->folder
examples 4339364 --->folder
fbc.exe 2015232
inc 26792897 --->folder
lib 85030482 --->folder
readme.txt 12130
__________________
Total size 145812214
Files 4051
Folders 250
DONE . . .
#define isfolder(path) fileexists(path)=0
#define isfile(path) fileexists(path)
It is slightly slower.
Tested win 32, win 64 and gas64.