【问题标题】:How To Get Directory Size With Swift On OS X如何在 OS X 上使用 Swift 获取目录大小
【发布时间】:2015-12-25 04:42:16
【问题描述】:

我正在尝试使用 Swift 获取目录的大小以及它在 OS X 上的内容。到目前为止,我只能获得目录本身的大小,没有任何内容。对于我的大多数目录,它通常显示 6,148 字节的值,但它确实有所不同。

我已经尝试了下面文件中的 directorySize() 函数,但它也返回了 6,148 个字节。

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

我尝试了这个问题的前 2 个答案,但不确定它需要什么参数将 Swift 传递给 Objective-C 函数。我相信它需要一个指针(我是一个正在学习的初级程序员)。

Calculate the size of a folder

我也无法从这里得到 Swift 的答案来达到我的目的。

How to get the file size given a path?

我正在使用 Xcode 7.0 并运行 OS X 10.10.5。

【问题讨论】:

    标签: macos swift swift2 nsfilemanager


    【解决方案1】:

    更新: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()
    }
    

    用法:

    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)
    }
    

    【讨论】:

    【解决方案2】:

    这里是 Swift 3 版本:

     func findSize(path: String) throws -> UInt64 {
    
        let fullPath = (path as NSString).expandingTildeInPath
        let fileAttributes: NSDictionary = try FileManager.default.attributesOfItem(atPath: fullPath) as NSDictionary
    
        if fileAttributes.fileType() == "NSFileTypeRegular" {
            return fileAttributes.fileSize()
        }
    
        let url = NSURL(fileURLWithPath: fullPath)
        guard let directoryEnumerator = FileManager.default.enumerator(at: url as URL, includingPropertiesForKeys: [URLResourceKey.fileSizeKey], options: [.skipsHiddenFiles], errorHandler: nil) else { throw FileErrors.BadEnumeration }
    
        var total: UInt64 = 0
    
        for (index, object) in directoryEnumerator.enumerated() {
            guard let fileURL = object as? NSURL else { throw FileErrors.BadResource }
            var fileSizeResource: AnyObject?
            try fileURL.getResourceValue(&fileSizeResource, forKey: URLResourceKey.fileSizeKey)
            guard let fileSize = fileSizeResource as? NSNumber else { continue }
            total += fileSize.uint64Value
            if index % 1000 == 0 {
                print(".", terminator: "")
            }
        }
    
        if total < 1048576 {
            total = 1
        }
        else
        {
            total = UInt64(total / 1048576)
        }
    
        return total
    }
    
    enum FileErrors : ErrorType {
        case BadEnumeration
        case BadResource
    }
    

    输出值为兆字节。 从源转换:https://gist.github.com/rayfix/66b0a822648c87326645

    【讨论】:

    • 请注意,您还需要(来自引用的来源): enum FileErrors : Error { case BadEnumeration case BadResource }
    • 我还添加了 ErrorType 枚举。谢谢丹
    【解决方案3】:

    对于正在寻找 Swift 5+ 和 Xcode 11+ 解决方案的任何人,请查看gist

    func directorySize(url: URL) -> Int64 {
        let contents: [URL]
        do {
            contents = try FileManager.default.contentsOfDirectory(at: url, includingPropertiesForKeys: [.fileSizeKey, .isDirectoryKey])
        } catch {
            return 0
        }
    
        var size: Int64 = 0
    
        for url in contents {
            let isDirectoryResourceValue: URLResourceValues
            do {
                isDirectoryResourceValue = try url.resourceValues(forKeys: [.isDirectoryKey])
            } catch {
                continue
            }
    
            if isDirectoryResourceValue.isDirectory == true {
                size += directorySize(url: url)
            } else {
                let fileSizeResourceValue: URLResourceValues
                do {
                    fileSizeResourceValue = try url.resourceValues(forKeys: [.fileSizeKey])
                } catch {
                    continue
                }
    
                size += Int64(fileSizeResourceValue.fileSize ?? 0)
            }
        }
        return size
    

    }

    【讨论】:

      【解决方案4】:

      对于任何寻找准系统实现的人(在 macOS 和 iOS 上工作相同):

      Swift 5 准系统版本

      extension URL {
          var fileSize: Int? { // in bytes
              do {
                  let val = try self.resourceValues(forKeys: [.totalFileAllocatedSizeKey, .fileAllocatedSizeKey])
                  return val.totalFileAllocatedSize ?? val.fileAllocatedSize
              } catch {
                  print(error)
                  return nil
              }
          }
      }
      
      extension FileManager {
          func directorySize(_ dir: URL) -> Int? { // in bytes
              if let enumerator = self.enumerator(at: dir, includingPropertiesForKeys: [.totalFileAllocatedSizeKey, .fileAllocatedSizeKey], options: [], errorHandler: { (_, error) -> Bool in
                  print(error)
                  return false
              }) {
                  var bytes = 0
                  for case let url as URL in enumerator {
                      bytes += url.fileSize ?? 0
                  }
                  return bytes
              } else {
                  return nil
              }
          }
      }
      

      用法

      let fm = FileManager.default
      let tmp = fm.temporaryDirectory
      
      if let size = fm.directorySize(tmp) {
          print(size)
      }
      

      是什么让这个准系统:不预先检查目录是目录还是文件是文件(无论哪种方式都返回nil),结果以其本机格式返回(字节为整数)。

      【讨论】:

        【解决方案5】:

        Swift 3 版本

        private func sizeToPrettyString(size: UInt64) -> String {
        
            let byteCountFormatter = ByteCountFormatter()
            byteCountFormatter.allowedUnits = .useMB
            byteCountFormatter.countStyle = .file
            let folderSizeToDisplay = byteCountFormatter.string(fromByteCount: Int64(size))
        
            return folderSizeToDisplay
        
        }
        

        【讨论】:

          猜你喜欢
          • 2023-03-23
          • 1970-01-01
          • 2017-01-31
          • 2010-09-27
          • 2017-08-24
          • 1970-01-01
          • 2011-03-17
          • 2011-03-02
          • 1970-01-01
          相关资源
          最近更新 更多