如何检测iPhone / iPad设备上的可用/可用磁盘空间总量?
我正在寻找一种更好的方式来以编程方式检测iPhone / iPad设备上的可用/可用磁盘空间。
目前我正在使用NSFileManager来检测磁盘空间。 以下是代码为我做的工作片段:
-(unsigned)getFreeDiskspacePrivate { NSDictionary *atDict = [[NSFileManager defaultManager] attributesOfFileSystemForPath:@"/" error:NULL]; unsigned freeSpace = [[atDict objectForKey:NSFileSystemFreeSize] unsignedIntValue]; NSLog(@"%s - Free Diskspace: %u bytes - %u MiB", __PRETTY_FUNCTION__, freeSpace, (freeSpace/1024)/1024); return freeSpace; }
我正确与上面的片段? 还是有更好的方法来知道总的可用/可用磁盘空间。
我必须检测总可用磁盘空间,因为我们必须阻止我们的应用程序在低磁盘空间情况下执行同步。
更新 :由于很多时间已经过了这个答案和新的方法/ APIs已被添加,请检查下面的Swift等更新的答案; 由于我自己没有用过,所以我不能担保。
原来的答案 :我发现以下解决scheme为我工作:
-(uint64_t)getFreeDiskspace { uint64_t totalSpace = 0; uint64_t totalFreeSpace = 0; NSError *error = nil; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error]; if (dictionary) { NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize]; NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize]; totalSpace = [fileSystemSizeInBytes unsignedLongLongValue]; totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue]; NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll)); } else { NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %ld", [error domain], (long)[error code]); } return totalFreeSpace; }
当设备连接到机器时,它会返回iTunes正好显示的大小。
使用unsigned long long修改源码:
- (uint64_t)freeDiskspace { uint64_t totalSpace = 0; uint64_t totalFreeSpace = 0; __autoreleasing NSError *error = nil; NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths lastObject] error: &error]; if (dictionary) { NSNumber *fileSystemSizeInBytes = [dictionary objectForKey: NSFileSystemSize]; NSNumber *freeFileSystemSizeInBytes = [dictionary objectForKey:NSFileSystemFreeSize]; totalSpace = [fileSystemSizeInBytes unsignedLongLongValue]; totalFreeSpace = [freeFileSystemSizeInBytes unsignedLongLongValue]; NSLog(@"Memory Capacity of %llu MiB with %llu MiB Free memory available.", ((totalSpace/1024ll)/1024ll), ((totalFreeSpace/1024ll)/1024ll)); } else { NSLog(@"Error Obtaining System Memory Info: Domain = %@, Code = %d", [error domain], [error code]); } return totalFreeSpace; }
编辑:它似乎有人编辑此代码使用'uint64_t',而不是'无符号长期的'。 虽然在可预见的将来,这应该是好的,他们是不一样的。 'uint64_t'是64位,将永远是。 在10年的“无名长龙”可能是128.这是一个小点,但为什么我用无符号龙珑。
如果你需要格式化的string大小,你可以看看GitHub上的漂亮的库 :
#define MB (1024*1024) #define GB (MB*1024) @implementation ALDisk #pragma mark - Formatter + (NSString *)memoryFormatter:(long long)diskSpace { NSString *formatted; double bytes = 1.0 * diskSpace; double megabytes = bytes / MB; double gigabytes = bytes / GB; if (gigabytes >= 1.0) formatted = [NSString stringWithFormat:@"%.2f GB", gigabytes]; else if (megabytes >= 1.0) formatted = [NSString stringWithFormat:@"%.2f MB", megabytes]; else formatted = [NSString stringWithFormat:@"%.2f bytes", bytes]; return formatted; } #pragma mark - Methods + (NSString *)totalDiskSpace { long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue]; return [self memoryFormatter:space]; } + (NSString *)freeDiskSpace { long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue]; return [self memoryFormatter:freeSpace]; } + (NSString *)usedDiskSpace { return [self memoryFormatter:[self usedDiskSpaceInBytes]]; } + (CGFloat)totalDiskSpaceInBytes { long long space = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemSize] longLongValue]; return space; } + (CGFloat)freeDiskSpaceInBytes { long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue]; return freeSpace; } + (CGFloat)usedDiskSpaceInBytes { long long usedSpace = [self totalDiskSpaceInBytes] - [self freeDiskSpaceInBytes]; return usedSpace; }
我已经写了一个类来使用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 } } }
演示
不要使用'unsigned',只有32位会溢出4GB以上,这比典型的iPad / iPhone空闲空间less。 使用unsigned long long(或uint64_t),并使用unsignedLongLongValue将值从NSNumber中作为一个64位int进行检索。
如果你想使用Swift来获得剩余的空间,它会稍微有点不同。 您需要使用attributesOfFileSystemForPath()而不是attributesOfItemAtPath():
func deviceRemainingFreeSpaceInBytes() -> Int64? { let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) var attributes: [String: AnyObject] do { attributes = try NSFileManager.defaultManager().attributesOfFileSystemForPath(documentDirectoryPath.last! as String) let freeSize = attributes[NSFileSystemFreeSize] as? NSNumber if (freeSize != nil) { return freeSize?.longLongValue } else { return nil } } catch { return nil } }
编辑:更新为Swift 1.0
编辑2:更新的安全性, 使用马丁R的答案 。
编辑3:更新为Swift 2.0(由dgellow )
这是我的答案,为什么更好。
答案(Swift):
func remainingDiskSpaceOnThisDevice() -> String { var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.") if let attributes = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()), let freeSpaceSize = attributes[FileAttributeKey.systemFreeSize] as? Int64 { remainingSpace = ByteCountFormatter.string(fromByteCount: freeSpaceSize, countStyle: .file) } return remainingSpace }
答案(Objective-C):
- (NSString *)calculateRemainingDiskSpaceOnThisDevice { NSString *remainingSpace = NSLocalizedString(@"Unknown", @"The remaining free disk space on this device is unknown."); NSDictionary *dictionary = [[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil]; if (dictionary) { long long freeSpaceSize = [[dictionary objectForKey:NSFileSystemFreeSize] longLongValue]; remainingSpace = [NSByteCountFormatter stringFromByteCount:freeSpaceSize countStyle:NSByteCountFormatterCountStyleFile]; } return remainingSpace; }
为什么更好:
- 使用Cocoa内置的库
NSByteCountFormatter
,这意味着从字节到千兆字节没有疯狂的手动计算。 苹果为你做这个! - 轻松翻译:
NSByteCountFormatter
为您做到这一点。 例如,当设备的语言设置为英文时,string将读取248.8 MB,但在设置为法语时将读取248.8个Mo,等等用于其他语言。 - 出现错误时会给出默认值。
重要的澄清(至less对我来说)。 如果我将iPod连接到我的Mac上,这是iTunes App显示的信息。
当我使用上面的代码:
long long freeSpace = [[[[NSFileManager defaultManager] attributesOfFileSystemForPath:NSHomeDirectory() error:nil] objectForKey:NSFileSystemFreeSize] longLongValue]; NSString *free1 = [NSByteCountFormatter stringFromByteCount:freeSpace countStyle:NSByteCountFormatterCountStyleFile]; [label1 setText:free1]; NSString *free2 = [NSByteCountFormatter stringFromByteCount:freeSpace countStyle:NSByteCountFormatterCountStyleBinary]; [label2 setText:free2];
countStyle NSByteCountFormatterCountStyleFile显示我:17,41 GB
countStyle NSByteCountFormatterCountStyleBinary显示我:16,22 GB
16,22 GB ( NSByteCountFormatterCountStyleBinary )当我将iPod连接到我的Mac时,它恰好是iTunes App显示的数字。
对于iOS> = 6.0,您可以使用新的NSByteCountFormatter
。 这段代码将剩余的空闲字节数作为一个格式化的string。
NSError *error = nil; NSArray * const paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSDictionary * const pathAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:[paths firstObject] error:&error]; NSAssert(pathAttributes, @""); NSNumber * const fileSystemSizeInBytes = [pathAttributes objectForKey: NSFileSystemFreeSize]; const long long numberOfBytesRemaining = [fileSystemSizeInBytes longLongValue]; NSByteCountFormatter *byteCountFormatter = [[NSByteCountFormatter alloc] init]; NSString *formattedNmberOfBytesRemaining = [byteCountFormatter stringFromByteCount:numberOfBytesRemaining];
以下代码是由ChrisJF以前提供的答案的Swift 3.0版本实现:
func freeSpaceInBytes() -> NSString { var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.") do { let dictionary = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory()) let freeSpaceSize = ((dictionary[FileAttributeKey.systemFreeSize] as AnyObject).longLongValue)! remainingSpace = ByteCountFormatter.string(fromByteCount: freeSpaceSize, countStyle: ByteCountFormatter.CountStyle.file) } catch let error { NSLog(error.localizedDescription) } return remainingSpace as NSString }
对于Swift UIDevice扩展
extension UIDevice { func freeDiskspace() -> NSString { let failedResult: String = "Error Obtaining System Memory" guard let path = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true).last else { return failedResult } do { let dictionary = try NSFileManager.defaultManager().attributesOfFileSystemForPath(path) if let fileSystemSizeInBytes = dictionary[NSFileSystemSize] as? UInt, let freeFileSystemSizeInBytes = dictionary[NSFileSystemFreeSize] as? UInt { return "Memory \(freeFileSystemSizeInBytes/1024/1024) of \(fileSystemSizeInBytes/1024/1024) Mb available." } else { return failedResult } } catch { return failedResult } } }
如何使用:
print("\(UIDevice.currentDevice().freeDiskspace())")
输出将是:
Memory 9656 of 207694 Mb available.
我知道这个post有点旧了,但是我觉得这个答案可以帮助别人。 如果您想知道设备上已用/自由/总磁盘空间,可以使用Luminous 。 它是用Swift编写的。 你只需要打电话给:
Luminous.System.Disk.freeSpace() Luminous.System.Disk.usedSpace()
要么
Luminous.System.Disk.freeSpaceInBytes() Luminous.System.Disk.usedSpaceInBytes()
ChrisJF在Swift 2.1版本中回答:
func freeSpaceInBytes() -> NSString{ var remainingSpace = NSLocalizedString("Unknown", comment: "The remaining free disk space on this device is unknown.") do { let dictionary = try NSFileManager.defaultManager().attributesOfFileSystemForPath(NSHomeDirectory()) freeSpaceSize = (dictionary[NSFileSystemFreeSize]?.longLongValue)! remainingSpace = NSByteCountFormatter.stringFromByteCount(freeSpaceSize, countStyle: NSByteCountFormatterCountStyle.File) } catch let error as NSError { error.description NSLog(error.description) } return remainingSpace }
上面代码的快速实现: –
import UIKit class DiskInformation: NSObject { var totalSpaceInBytes: CLongLong = 0; // total disk space var totalFreeSpaceInBytes: CLongLong = 0; //total free space in bytes func getTotalDiskSpace() -> String { //get total disk space do{ let space: CLongLong = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemSize] as! CLongLong; //Check for home dirctory and get total system size totalSpaceInBytes = space; // set as total space return memoryFormatter(space: space); // send the total bytes to formatter method and return the output }catch let error{ // Catch error that may be thrown by FileManager print("Error is ", error); } return "Error while getting memory size"; } func getTotalFreeSpace() -> String{ //Get total free space do{ let space: CLongLong = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemFreeSize] as! CLongLong; totalFreeSpaceInBytes = space; return memoryFormatter(space: space); }catch let error{ print("Error is ", error); } return "Error while getting memory size"; } func getTotalUsedSpace() -> String{ //Get total disk usage from above variable return memoryFormatter(space: (totalSpaceInBytes - totalFreeSpaceInBytes)); } func memoryFormatter(space : CLongLong) -> String{ //Format the usage to return value with 2 digits after decimal var formattedString: String; let totalBytes: Double = 1.0 * Double(space); let totalMb: Double = totalBytes / (1024 * 1024); let totalGb: Double = totalMb / 1024; if (totalGb > 1.0){ formattedString = String(format: "%.2f", totalGb); }else if(totalMb >= 1.0){ formattedString = String(format: "%.2f", totalMb); }else{ formattedString = String(format: "%.2f", totalBytes); } return formattedString; } }
从任何其他课程调用它。
func getDiskInfo(){ let diskInfo = DiskInformation(); print("Total disk space is", diskInfo.getTotalDiskSpace(),"Gb"); print("Total free space is", diskInfo.getTotalFreeSpace(),"Gb"); print("Total used space is", diskInfo.getTotalUsedSpace(),"Gb"); }
在testing返回的值时,它与其他应用程序显示的一样。 至less在我的iPhone 6S +。 这只是上面显示的答案的快速实施。 而对于我来说,接受的答案是行不通的。
更新一个新的准确的API,以获得可用的iOS11磁盘大小。 以下是新的API资源键的描述:
#if os(OSX) || os(iOS) /// 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. @available(OSX 10.13, iOS 11.0, *) @available(tvOS, unavailable) @available(watchOS, unavailable) public var volumeAvailableCapacityFor Usage: Int64? { return _get(.volumeAvailableCapacityForImportantUsageKey) } #endif
我交叉比较了关键“ FileAttributeKey.systemFreeSize ”和关键“ URLResourceKey.volumeAvailableCapacityForImportantUsageKey ”的结果,发现从“ volumeAvailableCapacityForImportantUsageKey ”返回的结果与UI上显示的可用存储完全匹配。 这是快速的实现:
class var freeDiskSpaceInBytesImportant:Int64 { get { do { return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage! } catch { return 0 } } }
如果你想节省时间,使用下面的CocoaPod库。 我没有使用它,但似乎应该工作。