Search code examples
swiftmacosdirectorynsfilemanagerfilesize

How To Get Directory Size With Swift On OS X


I am trying to get the size of a directory, as well as it's content on OS X using Swift. So far, I have only been able to get the size of the directory itself, with none of it's content. For most of my directories it generally shows a value of 6,148 bytes but it does vary.

I have tried the directorySize() function from the file below but it returned 6,148 bytes as well.

https://github.com/amosavian/ExtDownloader/blob/2f7dba2ec1edd07282725ff47080e5e7af7dabea/Utility.swift

And I could not get the Swift answer from here to work for my purpose either.

How to get the file size given a path?

I am using Xcode 7.0 and running OS X 10.10.5.


Solution

  • update: Xcode 11.4.1 • Swift 5.2


    extension URL {
        /// check if the URL is a directory and if it is reachable 
        func isDirectoryAndReachable() throws -> Bool {
            guard try resourceValues(forKeys: [.isDirectoryKey]).isDirectory == true else {
                return false
            }
            return try checkResourceIsReachable()
        }
    
        /// returns total allocated size of a the directory including its subFolders or not
        func directoryTotalAllocatedSize(includingSubfolders: Bool = false) throws -> Int? {
            guard try isDirectoryAndReachable() else { return nil }
            if includingSubfolders {
                guard
                    let urls = FileManager.default.enumerator(at: self, includingPropertiesForKeys: nil)?.allObjects as? [URL] else { return nil }
                return try urls.lazy.reduce(0) {
                        (try $1.resourceValues(forKeys: [.totalFileAllocatedSizeKey]).totalFileAllocatedSize ?? 0) + $0
                }
            }
            return try FileManager.default.contentsOfDirectory(at: self, includingPropertiesForKeys: nil).lazy.reduce(0) {
                     (try $1.resourceValues(forKeys: [.totalFileAllocatedSizeKey])
                        .totalFileAllocatedSize ?? 0) + $0
            }
        }
    
        /// returns the directory total size on disk
        func sizeOnDisk() throws -> String? {
            guard let size = try directoryTotalAllocatedSize(includingSubfolders: true) else { return nil }
            URL.byteCountFormatter.countStyle = .file
            guard let byteCount = URL.byteCountFormatter.string(for: size) else { return nil}
            return byteCount + " on disk"
        }
        private static let byteCountFormatter = ByteCountFormatter()
    }
    

    usage:

    do {
        let documentDirectory = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
        if let sizeOnDisk = try documentDirectory.sizeOnDisk() {
            print("Size:", sizeOnDisk) // Size: 3.15 GB on disk
        }
    } catch {
        print(error)
    }