Is it possible to get Folder Size?

BlitzMax Forums/BlitzMax Programming/Is it possible to get Folder Size?

ima747(Posted 2007) [#1]
The FileSize function can be run on folders but it returns somewhat random results it seems. Is there any way to get the size of a folder? For my needs it doesn't need to be very acurate. Preferably cross system friendly... doing a recursive scan of a directory for file sizes can obviously take forever if you try doing it on a directory that's too low (i.e. the root of a drive).

Any thoughts? my searches have not turned up much of use.


FlameDuck(Posted 2007) [#2]
Do a recursive scan of all the files in the folder and it's subfolders, and add the size of all files to a running tally.


Space Fractal(Posted 2007) [#3]
Something like this (wich can of course been better):

FolderSize.Examine("Your Path")
Print "Size in KB: "+FolderSize.Size/1024


Type FolderSize
	Global Size
	
	Function Examine(Dir$, Root=1)
		Local files$[]
		Local Handler=ReadDir(Dir$)
		If Root=1 Then Size=0
		If Handler<>Null
			Repeat
				Local File$=NextFile(Handler)
				If File$="" Then Exit
				If FileType(Dir$+"\"+File$)=2
					Examine(Dir$+"\"+File$)
				Else
					Size:+FileSize(DIR$+"\"+File$)
				EndIf
			Forever
		EndIf
	EndFunction
EndType


Doing a recursive scan is the only the way to go. You cant do anything other, and I guess FileSIze does the same things?


ima747(Posted 2007) [#4]
I tried that before I posted unfortunatetly. It can take a rediculously long time to get a size. I was hoping someone knew of some way to tap into the numbers the OS stores (atleast on a mac) for folder sizes...


Space Fractal(Posted 2007) [#5]
Yes it take time, but even Windows Explorer does that, and it can been clearly seen when right clicking on a folde, and check that size.

But it does that in a seperate thread, but Blitz dosent support that.


marksibly(Posted 2007) [#6]
Hi,

Here's an interesting alternative.

Of course, you've got to keep 'poking' it, but even a multithreaded solution would required some kind of repetition.


Strict

Type TDirSize

	Method Done()
		Return _entry=_entries.length And _dirs.IsEmpty()
	End Method

	Method Update:Long()
		For Local count=1 To 2500
			While _entry=_entries.length
				If _dirs.IsEmpty() Return _size
				_dir=String( _dirs.RemoveLast() )
				_entries=LoadDir( _dir )
				_entry=0
			Wend
			Local path$=_dir+"/"+_entries[_entry]
			_entry:+1
			If FileType( path )=FILETYPE_DIR
				_dirs.AddLast path
			Else
				_size:+FileSize( path )
			EndIf
		Next
		Return _size
	End Method

	Function Create:TDirSize( dir$ )
		Assert FileType( dir )=FILETYPE_DIR
		Local t:TDirSize=New TDirSize
		t._dirs.AddLast dir
		Return t
	End Function
	
	Field _size:Long
	Field _dirs:TList=New TList
	Field _dir$,_entries$[],_entry
	
End Type

Local t:TDirSize=TDirSize.Create( "c:\" )

While Not t.Done()
	Print t.Update()
Wend

Print "Done!"
End



skn3(Posted 2007) [#7]
Filefunctions.bmx
Strict
Import brl.linkedlist
Import BRL.StandardIO
Import BRL.FileSystem

Function DirectorySize:Long(npath:String)
	'fix the path value
	npath = realdir(npath)
	
	'fix forward slashes
	npath = npath.replace("\","/")
	
	'create a list to store folder information
	Local temp_paths:TList = CreateList()
	Local temp_path:String
	Local temp_count:Long
	Local temp_dir:Int
	Local temp_file:String
	
	'add first instance to folder list
	temp_paths.addlast(npath)
	
	'start a scan in this folder
	While temp_paths.isempty() = False
		'grab first path and remove it
		temp_path = String(temp_paths.first())
		temp_paths.removefirst()
		
		Print "scanning: "+temp_path
		
		'scan through the path
		temp_dir = ReadDir(temp_path)
		Repeat
			temp_file = NextFile(temp_dir)
			If temp_file = "" Exit
			If temp_file = "." Or temp_file = ".." Continue

			Select FileType(temp_path + temp_file)
				Case 1
					'add the filesize to the count
					temp_count :+ FileSize(temp_path + temp_file)
				Case 2
					'add the path to list of paths to scan
					temp_paths.addlast(temp_path + temp_file + "/")
			End Select
		Forever
		CloseDir temp_dir
		
	Wend
	
	Return temp_count
End Function



Function ExtractPathSegments:String[](npath:String)
	Local temp_segments:String[]
	Local temp_count:Int
	Local temp_pos:Int
	Local temp_segment:String
	Local temp_subpos:Int
	Local temp_subsegment1:String
	Local temp_subsegment2:String

	'fix dotted paths
	npath = realdir(npath)
	
	'fix forward slashes
	npath = npath.replace("/","\")
	
	temp_pos = npath.find("\")
	While temp_pos <> -1
		'extract the segment
		temp_segment = npath[..temp_pos]
		
		'check to see if segment needs splitting
		temp_subpos = temp_segment.find(":")
		If temp_subpos = -1
			'no split needed
			
			'resize segment array
			temp_segments = temp_segments[..temp_count+1]
			
			'set segment
			temp_segments[temp_count] = temp_segment
			
			'increase segment count
			temp_count :+ 1
		Else
			'needs splitting
			
			temp_subsegment1 = temp_segment[..temp_subpos]
			temp_subsegment2 = temp_segment[temp_subpos+1..]
			
			'check to see for drive name
			If temp_subsegment2.length = 0
				'this is a correctly formed path so extract drive name
				'resize segment array
				temp_segments = temp_segments[..temp_count+1]
				
				'set segment
				temp_segments[temp_count] = temp_subsegment1 + ":"
				
				'increase segment count
				temp_count :+ 1
			Else
				'path missed out backslash after drive name
				'resize segment array
				temp_segments = temp_segments[..temp_count+2]
				
				'set segments
				temp_segments[temp_count] = temp_subsegment1
				temp_segments[temp_count+1] = temp_subsegment2
				
				'increase segment count
				temp_count :+ 2
			End If
		End If
		
		npath = npath[temp_pos+1..]
		temp_pos = npath.find("\")
	Wend
	'add last
	temp_segment = npath
	
	'check to see if segment needs splitting
	temp_subpos = temp_segment.find(":")
	If temp_subpos = -1
		'no split needed
		
		'resize segment array
		temp_segments = temp_segments[..temp_count+1]
		
		'set segment
		temp_segments[temp_count] = temp_segment
		
		'increase segment count
		temp_count :+ 1
	Else
		'needs splitting
		
		temp_subsegment1 = temp_segment[..temp_subpos]
		temp_subsegment2 = temp_segment[temp_subpos+1..]
		
		'check to see for drive name
		If temp_subsegment2.length = 0
			'this is a correctly formed path so extract drive name
			'resize segment array
			temp_segments = temp_segments[..temp_count+1]
			
			'set segment
			temp_segments[temp_count] = temp_subsegment1 + ":"
			
			'increase segment count
			temp_count :+ 1
		Else
			'path missed out backslash after drive name
			'resize segment array
			temp_segments = temp_segments[..temp_count+2]
			
			'set segments
			temp_segments[temp_count] = temp_subsegment1
			temp_segments[temp_count+1] = temp_subsegment2
			
			'increase segment count
			temp_count :+ 2
		End If
	End If
	
	Return temp_segments
End Function

Function EmptyFolder:Int(npath:String)
	'fix the path
	npath = realdir(npath)

	'check to see if folder exists
	If FileType(npath) <> 2
		' folder doesn't exist so return false
		Return False
	Else
		'folder exists
		Local temp_folder:Int = ReadDir(npath)
		Local temp_file:String
		Local temp_path:String
		
		Repeat
			temp_file = NextFile(temp_folder)
			If temp_file = "" Exit
			If temp_file = "." Or temp_file = ".." Continue
			
			temp_path = npath + "/" + temp_file
			Select FileType(temp_path)
				Case 1
					DeleteFile(temp_path)
				Case 2
					DeleteDir(temp_path,True)
			End Select
		Forever
	End If
End Function

Function CreateFolderStructure(npath:String)
	Local temp_i:Int
	Local temp_segment:String
	Local temp_segments:String[]
	Local temp_count:Int
	Local temp_path:String
	
	'get path segments
	temp_segments = ExtractPathSegments(npath)
	
	'go through created segments and create structure
	If temp_segments.length > 0
		For temp_i = 0 Until temp_segments.length
			temp_segment = temp_segments[temp_i]
			
			'check to see what type if segment this is
			If temp_segment[1..2] = ":"
				'drive
				temp_path :+ temp_segment
			Else
				'folder
				'create the folder
				temp_path :+ "\" + temp_segment
				CreateDir(temp_path)
				SetFileMode(temp_path,%111111111)
			End If
		Next
	End If
End Function

Function FindFileInFolder:String(npath:String,nfile:String)
	'fix path
	npath = realdir(npath)

	'this function will find a file in a folder.
	Local temp_folder:Int = ReadDir(npath)
	Local temp_file:String
	Local temp_path:String
	Local temp_i:Int
	Local temp_until:Int
	Local temp_match:Int
	
	'fix case of nfile
	nfile = nfile.tolower()
	
	Repeat
		temp_file = NextFile(temp_folder).tolower()
		If temp_file = "" Exit
		If temp_file = "." Or temp_file = ".." Continue
		
		'check only files
		temp_path = npath + "/" + temp_file
		If FileType(temp_path) = 1
			'check to see for match in file name
			'check to see scanning until which size
			If nfile.length >= temp_file.length
				temp_until = temp_file.length
			Else
				temp_until = nfile.length
			End If
			
			'scan the strings for a match
			temp_match = True
			For temp_i = 0 Until temp_until
				If temp_file[temp_i] <> nfile[temp_i]
					temp_match = False
					Exit
				End If
			Next
			
			If temp_match = True
				Return temp_path
			End If
		End If
	Forever
	
	Return ""
End Function

Function MoveFile:Int(nfrom:String,nto:String)
	'this function will move a file from one place to another
	
	'fix paths
	nfrom = realdir(nfrom)
	nto = realdir(nto)
	
	'make sure from file exists
	If FileType(nfrom) <> 1 Return False
	
	'set nfrom permissions
	SetFileMode(nfrom,%111111111)
	
	'remove to file if it already exists
	If FileType(nto) = 1
		'set to file permissions
		SetFileMode(nto,%111111111)
		DeleteFile(nto)
		'check to see if couldnt delete
		If FileType(nto) = 1 Return False
	End If
	
	'copy nfrom to nto
	CopyFile(nfrom,nto)
	
	'delete nfrom
	DeleteFile(nfrom)
	
	'return that file was copied
	Return True
End Function

Function RealDir:String(npath:String)
	If npath.length > 0
		'this is a temporary fix for the blitzmax bug
		npath = npath.replace("\","/")
		npath = npath.replace("//","/")
		If npath[..1] = "/" npath = npath[2..]
	End If
	
	Return RealPath(npath)
End Function




tpathsizereport.bmx
Strict

Import BRL.FileSystem
Import BRL.LinkedList
Import BRL.StandardIO
Import BRL.System

Function CreatePathSizeReport:TList(npath:String,nfilter:Long=0)
	'fix the path value
	npath = RealPath(npath)
	
	'fix forward slashes
	npath = npath.replace("\","/")

	Local temp_list:TList = CreateList()
	RecurseDirectory(npath,temp_list,nfilter)
	Return temp_list
End Function

Function RecurseDirectory:Long(npath:String,nlist:TList Var,nfilter:Long Var)
	'this function will recurse a directory 
	Local temp_dir:Int = ReadDir(npath)
	Local temp_file:String
	Local temp_count:Long
	Local temp_returned:Long
	Local temp_item:tpathsizeitem
	
	temp_dir = ReadDir(npath)
	Repeat
		temp_file = NextFile(temp_dir)
		If temp_file = "" Exit
		If temp_file = "." Or temp_file = ".." Continue

		Select FileType(npath + temp_file)
			Case 1
				
				'add the filesize to the count
				temp_returned = FileSize(npath + temp_file)
				
				If temp_returned >= nfilter
				
					'add file instance to the list
					temp_item = New tpathsizeitem
					temp_item.file = True
					temp_item.path = npath + temp_file
					temp_item.size = temp_returned
					
					'add to list
					nlist.addlast(temp_item)
				End If
				
				'increase count for return
				temp_count :+ temp_returned
			Case 2
				'recurse sub folder
				temp_returned = RecurseDirectory(npath + temp_file + "/",nlist,nfilter)
				
				If temp_returned >= nfilter
					'add folder instance to the list
					temp_item = New tpathsizeitem
					temp_item.file = False
					temp_item.path = npath + temp_file
					temp_item.size = temp_returned
					
					'add to list
					nlist.addlast(temp_item)
				End If
				
				'increase count for return
				temp_count :+ temp_returned
		End Select
		
		Delay 1
	Forever
	CloseDir temp_dir
	
	Return temp_count
End Function

Type tpathsizeitem
	Field file:Byte
	Field path:String
	Field size:Long
End Type



Enjoy!