seguridad - ¿Cómo detectar el espacio total en el disco disponible/libre en el dispositivo iPhone/iPad?
no puedo hacer copia de seguridad en icloud (17)
Aclaración importante (al menos para mí). Si conecto mi iPod a mi Mac, esta es la información que muestra la aplicación de iTunes.
Cuando uso el código anterior:
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];
El countStyle NSByteCountFormatterCountStyleFile me muestra: 17,41 GB
El countStyle NSByteCountFormatterCountStyleBinary me muestra: 16,22 GB
16,22 GB ( NSByteCountFormatterCountStyleBinary ) EXACTAMENTE es el número que me muestra la aplicación iTunes cuando conecto mi iPod a mi Mac.
Estoy buscando una mejor manera de detectar el espacio de disco disponible / libre en el dispositivo iPhone / iPad mediante programación.
Actualmente estoy usando NSFileManager para detectar el espacio en disco. A continuación está el fragmento del código que hace el trabajo por mí:
-(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;
}
¿Estoy en lo correcto con el fragmento de arriba? o hay alguna forma mejor de conocer el espacio total en disco disponible / libre.
Debo detectar el espacio total libre en el disco, ya que debemos evitar que nuestra aplicación realice la sincronización en el escenario de poco espacio en disco.
Actualice con una nueva API precisa para obtener el tamaño disponible en el disco disponible en iOS11. Aquí está la descripción de la nueva clave de recursos 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
Hice una comparación cruzada de los resultados de la clave " FileAttributeKey.systemFreeSize " y clave " URLResourceKey.volumeAvailableCapacityForImportantUsageKey " y encontré que los resultados devueltos de " volumeAvailableCapacityForImportantUsageKey " coinciden exactamente con el almacenamiento disponible que se muestra en la IU. Aquí está la implementación rápida:
class var freeDiskSpaceInBytesImportant:Int64 {
get {
do {
return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage!
} catch {
return 0
}
}
}
Aquí está mi respuesta y por qué es mejor.
Respuesta (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
}
Respuesta (Objetivo-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;
}
Por qué es mejor:
- Utiliza la biblioteca incorporada de Cocoa
NSByteCountFormatter
, lo que significa que no hay cálculos manuales locos de bytes a gigabytes. Apple hace esto por ti! - Fácilmente traducible:
NSByteCountFormatter
hace esto por usted. Por ejemplo, cuando el idioma del dispositivo está configurado en inglés, la cadena leerá 248,8 MB pero leerá 248,8 Mo cuando se configure en francés, etc. para otros idiomas. - Se proporciona un valor predeterminado en caso de error.
El siguiente código es la implementación de la versión Swift 3.0 de la respuesta proporcionada previamente por 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
}
Escribí una clase para obtener memoria disponible / usada usando Swift. Demostración en: https://github.com/thanhcuong1990/swift-disk-status
Actualización para 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
}
}
}
Manifestación
Fuente revisada utilizando 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;
}
EDITAR: parece que alguien editó este código para usar ''uint64_t'' en lugar de ''unsigned long long''. Si bien en un futuro previsible esto debería estar bien, no son lo mismo. ''uint64_t'' es de 64 bits y siempre será eso. En 10 años ''unsigned long long'' podría ser 128. es un pequeño punto, pero por qué usé unsignedLongLong.
Implementación rápida del código anterior: -
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;
}
}
Llámalo desde cualquier otra clase.
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");
}
Al probar el valor devuelto, es el mismo que se muestra en otras aplicaciones. Al menos en mi iPhone 6S +. Es solo la implementación rápida de la respuesta que se muestra arriba. Y para mí, la respuesta aceptada no funcionó.
No use ''unsigned'', solo son 32 bits que se desbordarán más allá de 4GB, que es menor que el espacio libre típico de iPad / iPhone. Use unsigned long long (o uint64_t) y recupere el valor del NSNumber como un int de 64 bits también utilizando unsignedLongLongValue.
Para iOS> = 6.0 puede usar el nuevo NSByteCountFormatter
. Este código obtiene la cantidad de bytes libres restantes como una cadena formateada.
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];
Puede encontrar otra solución con Swift 4 y extension
que le ofrece una buena opción.
Aquí está la extensión 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"
}
}
Y uso de muestra:
UIDevice.current.totalDiskSpaceInBytes()
UIDevice.current.totalDiskSpace()
UIDevice.current.freeDiskSpaceInBytes()
UIDevice.current.freeDiskSpace()
UIDevice.current.usedDiskSpaceInBytes()
UIDevice.current.usedDiskSpace()
Respuesta de ChrisJF en la versión de 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
}
Sé que esta publicación es un poco vieja, pero creo que esta respuesta puede ayudar a alguien. Si desea conocer el espacio en disco usado / libre / total en el dispositivo, puede usar Luminous . Está escrito en Swift. Solo tienes que llamar:
Luminous.System.Disk.freeSpace()
Luminous.System.Disk.usedSpace()
o
Luminous.System.Disk.freeSpaceInBytes()
Luminous.System.Disk.usedSpaceInBytes()
Si buscas obtener el espacio libre restante con Swift, es un poco diferente. Necesita utilizar attributesOfFileSystemForPath () en lugar de 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
}
}
Editar: Actualizado para Swift 1.0
Editar 2: actualizado por seguridad, usando la respuesta de Martin R.
Editar 3: actualizado para Swift 2.0 (por dgellow )
Si desea ahorrar tiempo, use la siguiente Biblioteca CocoaPod. No lo usé, pero parece que debería funcionar.
Si necesita una cadena formateada con el tamaño, puede echar un vistazo a la buena biblioteca en 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;
}
para Swift como extensión 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
}
}
}
Cómo utilizar:
print("/(UIDevice.currentDevice().freeDiskspace())")
La salida será:
Memory 9656 of 207694 Mb available.
ACTUALIZACIÓN : dado que ha pasado mucho tiempo después de esta respuesta y se han agregado nuevos métodos / API, compruebe las respuestas actualizadas a continuación para Swift, etc. Como no los he usado yo mismo, no puedo responder por ellos.
Respuesta original : encontré la siguiente solución que funciona para mí:
-(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;
}
Me devuelve exactamente el tamaño que iTunes muestra cuando el dispositivo está conectado a la máquina.