How to use stat utility instead of subpathsOfDirectoryAtPath to calculate directory size

1.2k views Asked by At

I have been calculating directory sizes using subpathsOfDirectoryAtPath:: and have found it very sluggish. After copious amounts of research I came across the stat structure that can be used to achieve the desired results more quickly and efficiently. How can I use stat in swift to achieve this goal?

Here's my current file size calculation algorithm using subpathsOfDirectoryAtPath:::

func calcSize(pathToDir: String) -> (Int) {
let fm = NSFileManager.defaultManager()
    var size = 0
    let fileArray = (fm.subpathsOfDirectoryAtPath(pathToDir, error: nil)) as! [String]
    for file in fileArray {
        autoreleasepool({
        var fileDict: NSDictionary? = fm.attributesOfItemAtPath(pathToDir.stringByAppendingPathComponent(file), error: nil)
        size += Int(fileDict!.fileSize())
        })
    }
    return (size)
}

PS. all the results I found so far have answers in objective-c and C but not in swift.

2

There are 2 answers

2
tek3 On BEST ANSWER

Here is the sample usage in Swift:

var stat1 : stat  = stat()
var documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as! NSString
stat(documentsPath.fileSystemRepresentation,  &stat1)
println(stat1.st_size)

EDIT

  var stat1 : stat  = stat()
        var size = 0
        let fileArray = (NSFileManager.defaultManager().subpathsOfDirectoryAtPath(pathToDir as String, error: nil)) as! [String]
        for file in fileArray {

            var stat1 : stat  = stat()
            var filex =  (pathToDir as String) + "/" +  file as NSString
            stat(filex.fileSystemRepresentation,  &stat1)
            if stat(filex.fileSystemRepresentation,  &stat1) != 0 {
                println("Some error occured ")
            } else {
                println(stat1.st_size)
            }
            size += Int(Double(stat1.st_size))                
    }
}
0
Ken Thomases On

I would suggest that you use NSFileManager.enumeratorAtURL(_:includingPropertiesForKeys:options:errorHandler:). For the property keys, specify [NSURLTotalFileSizeKey] or, perhaps, [NSURLTotalFileAllocatedSizeKey] depending on what you're interested in. That will include other forks and file metadata that stat() won't.

You then enumerate the items in the directory, getting NSURLs for each. You query an individual NSURL's size by using resourceValuesForKeys(). (I would suggest using getResourceValue(_:forKey:), but that can be a bit awkward in Swift.)

The advantage of using this form of enumerator is that it can pre-fetch the size property as it enumerates the directory. That should end up being faster than stat(). Under the hood, it uses getdirentriesattr(), which combines directory enumeration with attribute querying.