如何检测 iPhone/iPad 设备上的总可用/空闲磁盘空间?

我正在寻找一种更好的方法,通过编程方式检测 iPhone/iPad 设备上的可用/空闲磁盘空间。
目前,我使用 NSFileManager 来检测磁盘空间。下面是为我完成这项工作的代码片段: < br >

-(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;
}


上面的代码是否正确? 还是有更好的方法来了解可用/空闲磁盘空间总量。
我必须检测总的可用磁盘空间,因为我们必须防止我们的应用程序在低磁盘空间情况下执行同步。

92490 次浏览

不要使用“ unsigned”,它只有32位,超过4GB 就会溢出,这比典型的 iPad/iPhone 免费空间要少。使用 unsignedLongLongValue (或 uint64 _ t) ,并使用 unsignedLongLongValue 从 NSNumber 中检索64位 int 值。

更新 : 由于这个答案已经过去了很长时间,并且新的方法/API 已经被添加,请检查下面更新的答案为 Swift 等; 由于我自己没有使用它们,我不能保证它们。

原答案 : 我发现下面的解决方案对我很有效:

-(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”而不是“ unsignedlong long”。虽然在可预见的未来,这应该是正常的,但它们是不一样的。“ uint64 _ t”是64位,并且永远是这个值。在10年内,“未签署的长期长期”可能是128。这是一个小问题,但为什么我使用无名的龙龙。

如果你需要带大小的格式化字符串,你可以看看 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;
}

对于 iOS > = 6.0,可以使用新的 NSByteCountFormatter。此代码获取格式化字符串剩余的空闲字节数。

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];

如果您希望获得剩余的空闲空间使用 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更新(由 唐吉洛)

重要的澄清(至少对我来说)。如果我把我的 iPod 连接到我的 Mac,这是 iTunes 应用程序显示的信息。

iPod memory informations from 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,41GB

CountStyle 计数格式计数样式二进制显示: 16,22GB

16,22 GB (计数格式计数样式二进制)当我把 iPod 连接到 Mac 时,iTunes 应用程序显示的数字是 没错

我用 Swift 编写了一个类来获取可用/使用的内存。 演示地址: < a href = “ https://github.com/thanhcuong1990/swift-disk-status”rel = “ norefrer”> https://github.com/thanhcuong1990/swift-disk-status
Swift 4更新。

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


class var freeDiskSpace:String {
get {
return ByteCountFormatter.string(fromByteCount: freeDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
}
}


class var usedDiskSpace:String {
get {
return ByteCountFormatter.string(fromByteCount: usedDiskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.file)
}
}




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


}

演示

get disk space status with 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
}

答案(目标 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;
}

为什么更好:

  • 利用可可的内置库 NSByteCountFormatter,意味着没有疯狂的手工计算字节到千兆字节。苹果为你做这一点!
  • 易于翻译: NSByteCountFormatter为您做到了这一点。例如。当设备的语言设置为英语时,字符串将读取248.8 MB,但设置为法语时将读取248.8 Mo,等等。
  • 如果出现错误,则给出默认值。

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


}

用于 斯威夫特作为 UIDdevice 扩展

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.

我知道这个帖子有点老,但我认为这个答案可以帮助某人。如果您想知道设备上的使用/空闲/总磁盘空间,可以使用 发光。是用斯威夫特语写的。你只需要打电话:

Luminous.System.Disk.freeSpace()
Luminous.System.Disk.usedSpace()

或者

Luminous.System.Disk.freeSpaceInBytes()
Luminous.System.Disk.usedSpaceInBytes()

以下代码是 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


}

以上代码的快速实现:-

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

在测试返回值时,它与其他应用程序显示的结果相同。至少在我的 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

我交叉比较了键“ SystemFreeSize”和键“ URLResourceKey.volumeAvailableCapacityForImportantUsageKey”的结果,发现返回的结果“ 容量”与 UI 上显示的可用存储完全匹配。 Available free disk space compare 以下是快速实施方案:

class var freeDiskSpaceInBytesImportant:Int64 {
get {
do {
return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage!
} catch {
return 0
}
}
}

如果希望节省时间,请使用以下 CocoaPod 库。我没用过,但看起来应该能用。

Https://cocoapods.org/pods/systemservices

通过使用 Swift 4extension,您可以找到另一种解决方案,这为您提供了一个很好的选择。

这是 UIDevice分机。

extension UIDevice {


func totalDiskSpaceInBytes() -> Int64 {
do {
guard let totalDiskSpaceInBytes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemSize] as? Int64 else {
return 0
}
return totalDiskSpaceInBytes
} catch {
return 0
}
}


func freeDiskSpaceInBytes() -> Int64 {
do {
guard let totalDiskSpaceInBytes = try FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())[FileAttributeKey.systemFreeSize] as? Int64 else {
return 0
}
return totalDiskSpaceInBytes
} catch {
return 0
}
}


func usedDiskSpaceInBytes() -> Int64 {
return totalDiskSpaceInBytes() - freeDiskSpaceInBytes()
}


func totalDiskSpace() -> String {
let diskSpaceInBytes = totalDiskSpaceInBytes()
if diskSpaceInBytes > 0 {
return ByteCountFormatter.string(fromByteCount: diskSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
}
return "The total disk space on this device is unknown"
}


func freeDiskSpace() -> String {
let freeSpaceInBytes = freeDiskSpaceInBytes()
if freeSpaceInBytes > 0 {
return ByteCountFormatter.string(fromByteCount: freeSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
}
return "The free disk space on this device is unknown"
}


func usedDiskSpace() -> String {
let usedSpaceInBytes = totalDiskSpaceInBytes() - freeDiskSpaceInBytes()
if usedSpaceInBytes > 0 {
return ByteCountFormatter.string(fromByteCount: usedSpaceInBytes, countStyle: ByteCountFormatter.CountStyle.binary)
}
return "The used disk space on this device is unknown"
}


}

使用说明:

UIDevice.current.totalDiskSpaceInBytes()
UIDevice.current.totalDiskSpace()
UIDevice.current.freeDiskSpaceInBytes()
UIDevice.current.freeDiskSpace()
UIDevice.current.usedDiskSpaceInBytes()
UIDevice.current.usedDiskSpace()

这里是适用于 FileManager的 Swift 5扩展,它具有正确的错误处理和无自动字符串转换(按照您的喜好将字节数转换为字符串)。也遵循 FileManager的命名。

extension FileManager {
func systemFreeSizeBytes() -> Result<Int64, Error> {
do {
let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
guard let freeSize = attrs[.systemFreeSize] as? Int64 else {
return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system free size"]))
}
return .success(freeSize)
} catch {
return .failure(error)
}
}


func systemSizeBytes() -> Result<Int64, Error> {
do {
let attrs = try attributesOfFileSystem(forPath: NSHomeDirectory())
guard let size = attrs[.systemSize] as? Int64 else {
return .failure(NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Can't retrieve system size"]))
}
return .success(size)
} catch {
return .failure(error)
}
}
}

示例用法:

let freeSizeResult = FileManager.default.systemFreeSizeBytes()
switch freeSizeResult {
case .failure(let error):
print(error)
case .success(let freeSize):
let freeSizeString = ByteCountFormatter.string(fromByteCount: freeSize, countStyle: .file)
print("free size: \(freeSizeString)")
}