使用 Swift 查询可用的 iOS 磁盘空间
Posted
技术标签:
【中文标题】使用 Swift 查询可用的 iOS 磁盘空间【英文标题】:Query Available iOS Disk Space with Swift 【发布时间】:2014-11-29 15:23:00 【问题描述】:我正在尝试使用 Swift
获取可用的 ios 设备存储空间。我找到了这个函数here
func deviceRemainingFreeSpaceInBytes() -> NSNumber
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
let systemAttributes = NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last as String, error: nil)
return systemAttributes[NSFileSystemFreeSize] as NSNumber
但是在编译时会给出这个错误:[NSObject : AnyObject]? does not have a member named 'subscript'
我相信这个错误是由提到的here 引起的,即attributesOfFileSystemForPath
返回一个可选字典(documentation)。我从一般意义上理解这个问题,但由于建议的解决方案涉及嵌套案例,我不太明白如何修复我感兴趣的功能(这对我很陌生 @987654328 并没有帮助@)。有人可以建议如何使该功能起作用吗?注意:我不确定原始功能是否经过作者测试,或者它是否在 xcode 6 beta 下工作,但据我所知,它在 GM 下不起作用。
【问题讨论】:
【参考方案1】:嗯,根据上面的代码:
let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
您可能会发现 usedSpace 不等于 iPhone 设置页面的值。这是因为在 iOS11 中,Apple 引入了“重要”资源的总可用容量(以字节为单位)。
“重要”资源的总可用容量(以字节为单位),包括 预计将通过清除非必要和缓存来清除的空间 资源。 “重要”是指用户或应用程序 显然希望出现在本地系统上,但最终 可更换。这将包括用户明确拥有的项目 通过 UI 请求,以及应用程序需要的资源 为了提供功能。
示例:用户发布的视频 已明确要求观看但尚未看完或 用户请求下载的音频文件。
这个值 不应该用于确定是否有空间 不可替代的资源。在不可替代的资源的情况下,总是 无论可用容量如何,都尝试保存资源,并且 尽可能优雅地处理失败。
为了获得与我们在 iPhone 设置页面中看到的完全相同的值,我们可以通过 volumeAvailableCapacityForImportantUsage
获得空闲空间if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage
return space ?? 0
您可以使用以下UIDevice extension:
Swift4
extension UIDevice
func MBFormatter(_ bytes: Int64) -> String
let formatter = ByteCountFormatter()
formatter.allowedUnits = ByteCountFormatter.Units.useMB
formatter.countStyle = ByteCountFormatter.CountStyle.decimal
formatter.includesUnit = false
return formatter.string(fromByteCount: bytes) as String
//MARK: Get String Value
var totalDiskSpaceInGB:String
return ByteCountFormatter.string(fromByteCount: totalDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
var freeDiskSpaceInGB:String
return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
var usedDiskSpaceInGB:String
return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.decimal)
var totalDiskSpaceInMB:String
return MBFormatter(totalDiskSpaceInBytes)
var freeDiskSpaceInMB:String
return MBFormatter(freeDiskSpaceInBytes)
var usedDiskSpaceInMB:String
return MBFormatter(usedDiskSpaceInBytes)
//MARK: Get raw value
var totalDiskSpaceInBytes:Int64
guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
let space = (systemAttributes[FileAttributeKey.systemSize] as? NSNumber)?.int64Value else return 0
return space
/*
Total available capacity in bytes for "Important" resources, including space expected to be cleared by purging non-essential and cached resources. "Important" means something that the user or application clearly expects to be present on the local system, but is ultimately replaceable. This would include items that the user has explicitly requested via the UI, and resources that an application requires in order to provide functionality.
Examples: A video that the user has explicitly requested to watch but has not yet finished watching or an audio file that the user has requested to download.
This value should not be used in determining if there is room for an irreplaceable resource. In the case of irreplaceable resources, always attempt to save the resource regardless of available capacity and handle failure as gracefully as possible.
*/
var freeDiskSpaceInBytes:Int64
if #available(iOS 11.0, *)
if let space = try? URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage
return space ?? 0
else
return 0
else
if let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value
return freeSpace
else
return 0
var usedDiskSpaceInBytes:Int64
return totalDiskSpaceInBytes - freeDiskSpaceInBytes
用法:
print("totalDiskSpaceInBytes: \(UIDevice.current.totalDiskSpaceInBytes)")
print("freeDiskSpace: \(UIDevice.current.freeDiskSpaceInBytes)")
print("usedDiskSpace: \(UIDevice.current.usedDiskSpaceInBytes)")
【讨论】:
这应该是2018年的最佳答案。【参考方案2】:iOS 11 更新
下面给出的答案在 iOS 11 下不再提供准确的结果。新的音量容量键可以传递给URL.resourceValues(forKeys:)
,它们提供的值与设备设置中可用的值相匹配。
static let volumeAvailableCapacityKey: URLResourceKey
卷可用容量的密钥(以字节为单位)。
static let volumeAvailableCapacityForImportantUsageKey: URLResourceKey
用于存储重要资源的卷可用容量(以字节为单位)的密钥(只读)。
static let volumeAvailableCapacityForOpportunisticUsageKey: URLResourceKey
用于存储非必要资源的卷可用容量的密钥(以字节为单位)(只读)。
static let volumeTotalCapacityKey: URLResourceKey
卷总容量的密钥(以字节为单位)(只读)。
来自Apple's documentation:
概述
在您尝试在本地存储大量数据之前,请先确认您有足够的存储容量。要获取卷的存储容量,请构造一个 URL(使用 URL 的实例),该 URL 引用要查询的卷上的对象,然后查询该卷。
决定使用哪种查询类型
要使用的查询类型取决于存储的内容。如果您根据用户请求或应用程序正常运行所需的资源(例如,用户将要观看的视频或游戏中下一关所需的资源)存储数据,请查询
volumeAvailableCapacityForImportantUsageKey
.但是,如果您以更具预测性的方式下载数据(例如,下载用户最近观看的电视剧的新剧集),请查询volumeAvailableCapacityForOpportunisticUsageKey
。构造查询
使用此示例作为构建您自己的查询的指南:
let fileURL = URL(fileURLWithPath: NSHomeDirectory() as String)
do
let values = try fileURL.resourceValues(forKeys: [.volumeAvailableCapacityForImportantUsageKey])
if let capacity = values.volumeAvailableCapacityForImportantUsage
print("Available capacity for important usage: \(capacity)")
else
print("Capacity is unavailable")
catch
print("Error retrieving capacity: \(error.localizedDescription)")
原答案
可选绑定与if let
在这里也可以工作。
我建议该函数返回一个可选的Int64
,以便它可以返回
nil
表示失败:
func deviceRemainingFreeSpaceInBytes() -> Int64?
let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)
if let systemAttributes = NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last as String, error: nil)
if let freeSize = systemAttributes[NSFileSystemFreeSize] as? NSNumber
return freeSize.longLongValue
// something failed
return nil
Swift 2.1 更新:
func deviceRemainingFreeSpaceInBytes() -> Int64?
let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).last!
guard
let systemAttributes = try? NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectory),
let freeSize = systemAttributes[NSFileSystemFreeSize] as? NSNumber
else
// something failed
return nil
return freeSize.longLongValue
Swift 3.0 更新:
func deviceRemainingFreeSpaceInBytes() -> Int64?
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).last!
guard
let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: documentDirectory),
let freeSize = systemAttributes[.systemFreeSize] as? NSNumber
else
// something failed
return nil
return freeSize.int64Value
用法:
if let bytes = deviceRemainingFreeSpaceInBytes()
print("free space: \(bytes)")
else
print("failed")
【讨论】:
太棒了,谢谢!我将不得不研究这个以确保我知道它是如何工作的/为什么工作,并且也感谢第二个版本。 为什么这些返回大约。 200mb (200495104) 的可用空间。虽然 iOS 不允许我拍照,而且我无法将 7mb 的视频保存到磁盘? 正如@LucèBrùlè 提到的,当我运行上面的代码时,同样的事情也会发生。显示大约 215089152 字节。但是当我签入显示几个字节的应用程序存储时。有什么方法可以找出准确的,就像在应用程序存储设置中显示的一样?提前致谢 嘿@SubinKKuriakose 我进行了大量研究,但实际上并没有真正准确的方法来获取剩余的可用空间。我想这与 iOS 在电量不足时开始清理东西有关,这实际上总是在变化。 我编辑了这个答案,以便在 iOS 11 上提供更准确的结果。【参考方案3】:这类似于 Martin 对 Swift 3.1 的回答,但已转换为 UIDevice
的扩展名,以便更轻松地访问它。
extension UIDevice
var systemSize: Int64?
guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
let totalSize = (systemAttributes[.systemSize] as? NSNumber)?.int64Value else
return nil
return totalSize
var systemFreeSize: Int64?
guard let systemAttributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String),
let freeSize = (systemAttributes[.systemFreeSize] as? NSNumber)?.int64Value else
return nil
return freeSize
获取空闲空间:
UIDevice.current.systemFreeSize
并获得总空间:
UIDevice.current.systemSize
【讨论】:
【参考方案4】:我编写了一个类来使用 Swift 获取可用/已用内存。 演示地址:https://github.com/thanhcuong1990/swift-disk-status
升级以支持 Swift 3。
import UIKit
class DiskStatus
//MARK: Formatter MB only
class func MBFormatter(_ bytes: Int64) -> String
let formatter = ByteCountFormatter()
formatter.allowedUnits = ByteCountFormatter.Units.useMB
formatter.countStyle = ByteCountFormatter.CountStyle.decimal
formatter.includesUnit = false
return formatter.string(fromByteCount: bytes) as String
//MARK: Get String Value
class var totalDiskSpace:String
get
return ByteCountFormatter.string(fromByteCount: totalDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
class var freeDiskSpace:String
get
return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
class var usedDiskSpace:String
get
return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
//MARK: Get raw value
class var totalDiskSpaceInBytes:Int64
get
do
let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
let space = (systemAttributes[FileAttributeKey.systemSize] as? NSNumber)?.int64Value
return space!
catch
return 0
class var freeDiskSpaceInBytes:Int64
get
do
let systemAttributes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory() as String)
let freeSpace = (systemAttributes[FileAttributeKey.systemFreeSize] as? NSNumber)?.int64Value
return freeSpace!
catch
return 0
class var usedDiskSpaceInBytes:Int64
get
let usedSpace = totalDiskSpaceInBytes - freeDiskSpaceInBytes
return usedSpace
演示:
【讨论】:
不错!我喜欢显示方面。 这很好并且帮助了我。谢谢! Xcode 7.3:Use of unresolved identifier 'ByteCountFormatter'
不幸的是,iPhone“关于”页面上的值不同以上是关于使用 Swift 查询可用的 iOS 磁盘空间的主要内容,如果未能解决你的问题,请参考以下文章