Как определить общее доступное / свободное дисковое пространство на устройстве 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;
}
Я прав с приведенным выше фрагментом? или есть ли лучший способ узнать общее доступное / свободное место на диске.
Я должен определить общее свободное место на диске, так как мы должны предотвратить наше приложение выполните синхронизацию в сценарии с низким объемом дискового пространства.
17 ответов:
обновление: поскольку прошло много времени после этого ответа и были добавлены новые методы/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; }EDIT: кажется, кто-то отредактировал этот код, чтобы использовать 'uint64_t' вместо 'unsigned long long'. Хотя в обозримом будущем это должно быть просто прекрасно, они не одинаковы. 'uint64_t' - это 64 бита и всегда будет таковым. Через 10 лет "unsigned long long" может быть 128. это небольшой момент, но почему я использовал unsignedLongLong.
Если вам нужна форматированная строка с размером, вы можете взглянуть на хорошая библиотека на 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 3import 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 } } }Demo
Не используйте "unsigned", это всего лишь 32 бита, которые будут переполняться за 4 ГБ, что меньше, чем типичное свободное пространство iPad/iPhone. Используйте unsigned long long (или uint64_t) и извлеките значение из NSNumber как 64-разрядный int, используя unsignedLongLongValue.
Если вы хотите получить оставшееся свободное пространство с помощью 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 (by 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-С):
- (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, что означает отсутствие сумасшедших ручных вычислений от байтов до гигабайт. Компания Apple делает это для вас!- легко переводимый:
NSByteCountFormatterделает это для вас. Например, когда язык устройства установлен на английский строка будет читать 248,8 МБ, но будет читать 248,8 мес при установке на французский язык и т. д. для других языков.- в случае ошибки задается значение по умолчанию.
важное уточнение (по крайней мере для меня). Если я подключу свой 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];графский стиль NSByteCountFormatterCountStyleFile покажите мне: 17,41 ГБ
графский стиль NSByteCountFormatterCountStyleBinary покажите мне: 16,22 ГБ
16,22 ГБ (NSByteCountFormatterCountStyleBinary) является ровно номер, который приложение iTunes показывает мне, когда я подключаю свой iPod к моему Mac.
для 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 3.0 ответа, ранее предоставленного ChrisJF:
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 }
обновление с новым точным 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 " точно соответствует доступному хранилищу, показанному на ПОЛЬЗОВАТЕЛЬСКИЙ ИНТЕРФЕЙС.
Вот быстрая реализация:
class var freeDiskSpaceInBytesImportant:Int64 { get { do { return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage! } catch { return 0 } } }
на Свифт как расширение 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.
Я знаю, что этот пост немного старый, но я думаю, что этот ответ может помочь кому-то. Если вы хотите знать, используемое/свободное/общее дисковое пространство на устройстве вы можете использовать световой. Это написано на быстром языке. Вам остается только позвонить:
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"); }при проверке возвращаемого значения, это так же, как и другие приложения. По крайней мере, в моем iPhone 6S+. Это просто быстрая реализация приведенного выше ответа. И для меня принятый ответ не сработал.
Если вы хотите сэкономить время, используйте следующую библиотеку CocoaPod. Я не использовал его, но кажется он должен работать.



Comments