Je recherche un meilleur moyen de détecter par programme l’espace disque disponible/libre sur le périphérique iPhone/iPad.
Actuellement, j'utilise NSFileManager pour détecter l'espace disque. Voici l'extrait du code qui fait le travail pour moi:
-(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;
}
Est-ce que je me trompe avec l'extrait ci-dessus? ou existe-t-il un meilleur moyen de connaître le total de l'espace disque disponible/libre?.
Je dois détecter l’espace disque total disponible, car nous n’empêcherons pas notre application d’effectuer la synchronisation dans le scénario d’espace disque insuffisant .
UPDATE: Comme cette réponse a pris beaucoup de temps et que de nouvelles méthodes/API ont été ajoutées, vérifiez les réponses mises à jour ci-dessous pour Swift, etc. Comme je ne les ai pas utilisées moi-même, je ne peux pas en garantir .
Réponse originale : J'ai trouvé la solution suivante qui fonctionne pour moi:
-(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;
}
Il me renvoie exactement la taille affichée par iTunes lorsque l'appareil est connecté à la machine.
Source révisée utilisant 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: il semble que quelqu'un ait édité ce code pour utiliser 'uint64_t' au lieu de 'unsigned long long'. Alors que dans un avenir prévisible, cela devrait aller, ils ne sont pas les mêmes. 'uint64_t' a 64 bits et le sera toujours. Dans 10 ans, «unsigned long long» pourrait être 128. C'est un petit point mais pourquoi j'ai utilisé unsignedLongLong.
Si vous avez besoin d'une chaîne formatée avec une taille, vous pouvez jeter un oeil à Belle bibliothèque sur 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;
}
J'ai écrit un cours pour obtenir de la mémoire disponible/utilisée avec Swift. Démo à: https://github.com/thanhcuong1990/Swift-disk-status
Swift 4 mis à jour.
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
}
}
}
Démo
N'utilisez pas 'unsigned', ce ne sont que 32 bits qui dépasseront 4 Go, ce qui est inférieur à l'espace libre typique d'un iPad/iPhone. Utilisez unsigned long long (ou uint64_t) et récupérez la valeur hors du NSNumber en tant qu'int 64 bits en utilisant unsignedLongLongValue.
Si vous cherchez à utiliser l’espace libre restant avec Swift, il est légèrement différent. Vous devez utiliser attributesOfFileSystemForPath () au lieu 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
}
}
Edit: mis à jour pour Swift 1.0
Edit 2: mis à jour pour des raisons de sécurité, en utilisant la réponse de Martin R .
Edit 3: mis à jour pour Swift 2.0 (par dgellow )
Voici ma réponse et pourquoi c'est mieux.
Réponse (rapide):
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
}
Réponse (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;
}
Pourquoi c'est mieux:
NSByteCountFormatter
intégrée à Cocoa, ce qui signifie qu'aucun calcul manuel fou d'octets en gigaoctets. Apple le fait pour vous!NSByteCountFormatter
le fait pour vous. Par exemple. Lorsque la langue de l'appareil est définie sur Anglais, la chaîne indiquera 248,8 Mo mais 248,8 Mo si elle est définie sur Français, et cetera dans les autres langues.Précision importante (du moins pour moi). Si je connecte mon iPod à mon Mac, voici les informations affichées par iTunes App.
Quand j'utilise le code ci-dessus:
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];
Le countStyle NSByteCountFormatterCountStyleFile me montrer: 17,41 Go
Le countStyle NSByteCountFormatterCountStyleBinary me montrer: 16,22 Go
16,22 Go ( NSByteCountFormatterCountStyleBinary ) Il s’agit duEXACTEMENTnuméro indiqué par l’application iTunes lorsque je connecte mon iPod à mon Mac.
Vous pouvez trouver une autre solution en utilisant Swift 4 et extension
qui vous donne une bonne option.
Voici l'extension 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"
}
}
Et exemple d'utilisation:
UIDevice.current.totalDiskSpaceInBytes()
UIDevice.current.totalDiskSpace()
UIDevice.current.freeDiskSpaceInBytes()
UIDevice.current.freeDiskSpace()
UIDevice.current.usedDiskSpaceInBytes()
UIDevice.current.usedDiskSpace()
Mise à jour avec une nouvelle API précise pour obtenir la taille disponible sur le disque disponible dans iOS11 . Voici la description de la nouvelle clé de ressource d'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
J'ai comparé les résultats de la clé "FileAttributeKey.systemFreeSize" et de la clé "URLResourceKey.volumeAvailableCapacityForImportantUsageKey" et a trouvé les résultats renvoyés sous la forme "volumeAvailableCapacityForImportantUsageKey" et correspond exactement à la mémoire disponible affichée Voici l'implémentation de Swift:
class var freeDiskSpaceInBytesImportant:Int64 {
get {
do {
return try URL(fileURLWithPath: NSHomeDirectory() as String).resourceValues(forKeys: [URLResourceKey.volumeAvailableCapacityForImportantUsageKey]).volumeAvailableCapacityForImportantUsage!
} catch {
return 0
}
}
}
Pour iOS> = 6.0, vous pouvez utiliser le nouveau NSByteCountFormatter
. Ce code obtient le nombre d'octets libres restants sous forme de chaîne mise en forme.
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];
Le code suivant est la mise en œuvre de la version 3.0 de la réponse fournie précédemment par 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
}
Je sais que ce post est un peu vieux, mais je pense que cette réponse peut aider quelqu'un. Si vous souhaitez connaître l'espace disque utilisé/libre/total sur le périphérique, vous pouvez utiliser Luminous . C'est écrit en Swift. Vous n'avez qu'à appeler:
Luminous.System.Disk.freeSpace()
Luminous.System.Disk.usedSpace()
ou
Luminous.System.Disk.freeSpaceInBytes()
Luminous.System.Disk.usedSpaceInBytes()
pour Swift comme extension 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
}
}
}
Comment utiliser:
print("\(UIDevice.currentDevice().freeDiskspace())")
La sortie sera:
Memory 9656 of 207694 Mb available.
Implémentation rapide du code ci-dessus: -
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;
}
}
Appelez-le de n'importe quelle autre classe.
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");
}
Tout en testant la valeur renvoyée, il est identique à celui affiché par d'autres applications. Au moins dans mon iPhone 6S +. C'est juste la mise en œuvre par Swift de la réponse indiquée ci-dessus. Et pour moi, la réponse acceptée ne fonctionnait pas.
Si vous voulez gagner du temps, utilisez la bibliothèque CocoaPod suivante. Je ne l'ai pas utilisé, mais il semble que cela devrait fonctionner.
ChrisJF answer in Swift 2.1 version:
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
}