【问题标题】:Get file size in Swift在 Swift 中获取文件大小
【发布时间】:2015-03-31 19:59:07
【问题描述】:

我尝试了几种方法来获取文件大小,但总是为零。

let path = NSBundle.mainBundle().pathForResource("movie", ofType: "mov")
let attr = NSFileManager.defaultManager().attributesOfFileSystemForPath(path!, error: nil)
if let attr = attr {
    let size: AnyObject? = attr[NSFileSize]
    println("File size = \(size)")
}

我进入日志:File size = nil

【问题讨论】:

  • 您确定该文件位于顶层的应用程序包中吗?
  • 或者尝试使用 attributesOfItemAtPath 而不是 attributesOfFileSystemForPath。您可以在 attr 上调用 .fileSize() 来获取文件大小。
  • @tyt_g207 我相信这是正确的解决方案,但您可能应该将其写为答案而不是评论,以便将来寻求答案的人更容易找到。

标签: ios swift


【解决方案1】:

使用attributesOfItemAtPath 而不是attributesOfFileSystemForPath + 在你的 attr 上调用 .fileSize()。

var filePath: NSString = "your path here"
var fileSize : UInt64
var attr:NSDictionary? = NSFileManager.defaultManager().attributesOfItemAtPath(filePath, error: nil)
if let _attr = attr {
    fileSize = _attr.fileSize();
}

在 Swift 2.0 中,我们使用 do try catch 模式,如下所示:

let filePath = "your path here"
var fileSize : UInt64 = 0

do {
    let attr : NSDictionary? = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)

    if let _attr = attr {
        fileSize = _attr.fileSize();
    }
} catch {
    print("Error: \(error)")
}

在 Swift 3.x/4.0 中:

let filePath = "your path here"
var fileSize : UInt64

do {
    //return [FileAttributeKey : Any]
    let attr = try FileManager.default.attributesOfItem(atPath: filePath)
    fileSize = attr[FileAttributeKey.size] as! UInt64

    //if you convert to NSDictionary, you can get file size old way as well.
    let dict = attr as NSDictionary
    fileSize = dict.fileSize()
} catch {
    print("Error: \(error)")
}

【讨论】:

  • 只有我认为 swift 2 让事情变得更糟了很多。我对 &error 非常满意。不是表达式的 try-catch 很糟糕。
  • 您始终可以使用try? 并获得可选的返回。
  • 这个结果是什么?我的是 f.e. 32768.0 这是字节吗??这么多 32KB?
  • @BrandonA 以字节为单位
【解决方案2】:

Swift4:方便访问文件属性的 URL 扩展

扩展名:

extension URL {
    var attributes: [FileAttributeKey : Any]? {
        do {
            return try FileManager.default.attributesOfItem(atPath: path)
        } catch let error as NSError {
            print("FileAttribute error: \(error)")
        }
        return nil
    }

    var fileSize: UInt64 {
        return attributes?[.size] as? UInt64 ?? UInt64(0)
    }

    var fileSizeString: String {
        return ByteCountFormatter.string(fromByteCount: Int64(fileSize), countStyle: .file)
    }

    var creationDate: Date? {
        return attributes?[.creationDate] as? Date
    }
}

用法:

let fileUrl: URL
print("file size = \(fileUrl.fileSize), \(fileUrl.fileSizeString)")

【讨论】:

  • URL直接用resourceValues(forKeys提供文件属性。
  • 这是最好的答案。应该是公认的答案
【解决方案3】:

在 Swift 3+ 中,您可以直接从 URL 获取文件大小,不需要 (NS)FileManager。而ByteCountFormatter 是一种显示文件大小的智能方式。

let url = Bundle.main.url(forResource:"movie", withExtension: "mov")!
do {
    let resourceValues = try url.resourceValues(forKeys: [.fileSizeKey])
    let fileSize = resourceValues.fileSize!
    print("File size = " + ByteCountFormatter().string(fromByteCount: Int64(fileSize)))
} catch { print(error) }

实际上,即使在 Swift 2 中,您也可以从 URL 获取文件大小,但语法有点麻烦。

【讨论】:

  • “是的,但是”资源值的 .fileSize 被定义为 Int,而 FileManager 的 .size 通过 NSNumber 以 unsigned long long 形式出现。无论如何不应该在不久的将来对 iOS 产生影响,但必须说。
  • 我认为使用Int 完全没问题,因为Apple 的产品几乎都是64 位的。一个通用的 Int 将能够适应所有可能的大小值。
【解决方案4】:

SWIFT 3 来自@Hoa 的回答,加上一个函数让 UInt64 可读字符串。

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
        if let fileSize = fileAttributes[FileAttributeKey.size]  {
            return (fileSize as! NSNumber).uint64Value
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}
func covertToFileString(with size: UInt64) -> String {
    var convertedValue: Double = Double(size)
    var multiplyFactor = 0
    let tokens = ["bytes", "KB", "MB", "GB", "TB", "PB",  "EB",  "ZB", "YB"]
    while convertedValue > 1024 {
        convertedValue /= 1024
        multiplyFactor += 1
    }
    return String(format: "%4.2f %@", convertedValue, tokens[multiplyFactor])
}

【讨论】:

  • 运行良好,除了一个关于covertToFileString 的错误。将while size > 1024 替换为while convertedValue > 1024 以避免无限循环
【解决方案5】:

这是来自 Biodave 的答案,带有正确的文件管理器调用

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try NSFileManager.defaultManager().attributesOfItemAtPath(filePath)
        if let fileSize = fileAttributes[NSFileSize]  {
            return (fileSize as! NSNumber).unsignedLongLongValue
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

对于 Swift 4.2:

func sizeForLocalFilePath(filePath:String) -> UInt64 {
    do {
        let fileAttributes = try FileManager.default.attributesOfItem(atPath: filePath)
        if let fileSize = fileAttributes[FileAttributeKey.size]  {
            return (fileSize as! NSNumber).uint64Value
        } else {
            print("Failed to get a size attribute from path: \(filePath)")
        }
    } catch {
        print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
    }
    return 0
}

【讨论】:

    【解决方案6】:

    Swift 4 解决方案: 此函数返回 MB 大小。

    func sizePerMB(url: URL?) -> Double {
        guard let filePath = url?.path else {
            return 0.0
        }
        do {
            let attribute = try FileManager.default.attributesOfItem(atPath: filePath)
            if let size = attribute[FileAttributeKey.size] as? NSNumber {
                return size.doubleValue / 1000000.0
            }
        } catch {
            print("Error: \(error)")
        }
        return 0.0
    }
    

    【讨论】:

    • 在我说出这句话之前,我真的很崩溃。做了几乎相同的事情,但没有使用 URL 的路径属性。谢谢,伙计!
    • 如何让它返回kb大小?
    【解决方案7】:

    在 Swift 中获取文件大小的 URL 扩展名,如果有的话。

    public extension URL {
    
        var fileSize: Int? {
            let value = try? resourceValues(forKeys: [.fileSizeKey])
            return value?.fileSize
        }
    }
    

    返回可选 Int 的原因是因为未知文件大小不能被视为具有零大小。

    【讨论】:

      【解决方案8】:

      这里有另外两种不同的 Swift 4 实现,一种是详细格式,另一种是十进制格式。

      NumberFomatter的那个:

      func fileSize(fromPath path: String) -> String? {
          var size: Any?
          do {
              size = try FileManager.default.attributesOfItem(atPath: path)[FileAttributeKey.size]
          } catch (let error) {
              print("File size error: \(error)")
              return nil
          }
          guard let fileSize = size as? UInt64 else {
              return nil
          }
      
          let formatter = NumberFormatter()
          formatter.numberStyle = .decimal
          formatter.formatterBehavior = .behavior10_4
          return formatter.string(from: NSNumber(value: fileSize))
      }
      

      另一个是用尺寸单位定义:

      func fileSize(fromPath path: String) -> String? {
          guard let size = try? FileManager.default.attributesOfItem(atPath: path)[FileAttributeKey.size],
              let fileSize = size as? UInt64 else {
              return nil
          }
      
          // bytes
          if fileSize < 1023 {
              return String(format: "%lu bytes", CUnsignedLong(fileSize))
          }
          // KB
          var floatSize = Float(fileSize / 1024)
          if floatSize < 1023 {
              return String(format: "%.1f KB", floatSize)
          }
          // MB
          floatSize = floatSize / 1024
          if floatSize < 1023 {
              return String(format: "%.1f MB", floatSize)
          }
          // GB
          floatSize = floatSize / 1024
          return String(format: "%.1f GB", floatSize)
      }
      

      【讨论】:

        【解决方案9】:

        试试这个。

        let MyUrl = NSURL(fileURLWithPath: "*** Custom File Path ***")                  
        let fileAttributes = try! NSFileManager.defaultManager().attributesOfItemAtPath(MyUrl.path!)
        let fileSizeNumber = fileAttributes[NSFileSize] as! NSNumber
        let fileSize = fileSizeNumber.longLongValue
        var sizeMB = Double(fileSize / 1024)
        sizeMB = Double(sizeMB / 1024)
        print(String(format: "%.2f", sizeMB) + " MB")
        

        【讨论】:

          【解决方案10】:

          在 Swift 3.0 中尝试以下操作:

          let fileSize = try! FileManager.default.attributesOfItem(atPath: "/bin/bash")[FileAttributeKey.size] as! Int
          

          甚至更好:

          let fileSize = (try! FileManager.default.attributesOfItem(atPath: "/bin/bash")[FileAttributeKey.size] as! NSNumber).uint64Value
          

          【讨论】:

          • 第二个怎么样?为什么不应该使用 NSNumber 自动转换?你也应该使用try?并作为?使用 if 或 guard 语句作为文件操作可能会失败。
          【解决方案11】:

          其他一些答案的启发。

          extension URL {
              var filesize: Int? {
                  let set = Set.init([URLResourceKey.fileSizeKey])
                  var filesize: Int?      
                  do {
                      let values = try self.resourceValues(forKeys: set)
                      if let theFileSize = values.fileSize {
                          filesize = theFileSize
                      }
                  }
                  catch {
                      print("Error: \(error)")
                  }
                  return filesize
              }
          
              var filesizeNicelyformatted: String? {
                  guard let fileSize = self.filesize else {
                      return nil
                  }
                  return ByteCountFormatter.init().string(fromByteCount: Int64(fileSize))
              }
          }
          

          【讨论】:

            【解决方案12】:

            这是一个通过 Xcode7 在 Swift 2.0 for iOS9 中编写为快乐方法的紧凑版本:

            func sizeForLocalFilePath(filePath:String) -> UInt64 {
                do {
                    let fileAttributes = try NSFileManager().attributesOfFileSystemForPath(filePath)
                    if let fileSize = fileAttributes[NSFileSystemSize] as? UInt64 {
                        return fileSize
                    } else {
                        print("Failed to get a size attribute from path: \(filePath)")
                    }
                } catch {
                    print("Failed to get file attributes for local path: \(filePath) with error: \(error)")
                }
                return 0
            }
            

            享受吧!

            【讨论】:

            • 这不起作用。它正在检查文件系统属性,而不是文件本身的属性。
            猜你喜欢
            • 2017-10-03
            • 2016-03-19
            • 2011-02-27
            • 2011-11-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多