【问题标题】:How to detect total available/free disk space on the iPhone/iPad device?如何检测 iPhone/iPad 设备上的总可用/空闲磁盘空间?
【发布时间】:2011-08-08 10:11:36
【问题描述】:

我正在寻找一种更好的方法来以编程方式检测 iPhone/iPad 设备上的可用/空闲磁盘空间。
目前我正在使用 NSFileManager 来检测磁盘空间。以下是为我完成这项工作的代码的 sn-p:

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


我对上面的 sn-p 是否正确?或者有没有更好的方法来了解总可用/可用磁盘空间。
我必须检测总可用磁盘空间,因为我们必须阻止我们的应用程序在磁盘空间不足的情况下执行同步。

【问题讨论】:

  • 希望stackoverflow link能帮到你..
  • 看起来他在他的问题中使用的代码比您给出的链接中的代码更好(他只是检查一个目录而不是遍历“/”下的所有子目录)
  • 感谢米哈伊尔提供的链接。但我正在寻找 iPhone/iPad 设备上的总可用/可用磁盘空间,而不仅仅是特定文件夹。例如,在 32GB 的 iPhone 上,如果总可用/空闲大小为 28GB,我应该能够以编程方式检测到。
  • 我希望这个链接有帮助:jayprakashdubey.blogspot.in/2014/07/…

标签: iphone ios ipad nsfilemanager diskspace


【解决方案1】:

不要使用“无符号”,它只有 32 位,会溢出超过 4GB,这比典型的 iPad/iPhone 可用空间要少。使用 unsigned long long(或 uint64_t),并使用 unsignedLongLongValue 从 NSNumber 中检索值作为 64 位 int。

【讨论】:

  • 它比提示更好 - “这是法律”:-) 正如他所说,原始代码完全错误。
【解决方案2】:

更新:由于这个答案已经过去了很长时间,并且添加了新的方法/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 显示的大小。

【讨论】:

  • 转换为浮点数可能会导致超过 2GB 的结果不准确。如果您需要处理非常大的文件大小,请改用 double 或 long double。
  • 正如 Ash 所指出的,这种方法的结果不准确。在我的 64GB 的 iPad 2 中,它失败了 +0.25GB... 下面的方法,由 David H 发布,在使用 uint64_t vars 时具有准确的结果。
  • 代码 sn-p 已被编辑以反映@David H 的建议,如下所示。
  • +200 MB 不是问题。在设置中,我有“0 字节”可用空间。当我进入并使用我的应用程序时,这种方法报告了大约 150mb 的可用空间。然后我填满了剩余的空间,然后应用程序崩溃了。所以我想说这种方法给你的信息比你在设置中看到的更正确。
  • 为什么没有人使用 NSUInteger 而不是 uint64_t 之类的东西?我们正在编写 Obj-C,而不是 C++ 或 C。NSUInteger 现在会给你一个无符号的 64 位整数,但如果事情发生变化,我想 Apple 会更新那个宏(假设某个时候 128 位成为现实)
【解决方案3】:

使用 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”而不是“unsigned long long”。虽然在可预见的未来这应该没问题,但它们并不相同。 'uint64_t' 是 64 位,并且永远都是。 10 年后,'unsigned long long' 可能是 128。这是一个小问题,但为什么我使用 unsignedLongLong。

【讨论】:

  • 我没有使用新的自动计数系统的经验,但是 __autoreleasing 有什么用?您通常不需要自动释放返回的 NSError
  • 这可能会有所帮助:stackoverflow.com/questions/8862023/…
  • 在我运行 iOS 5.1 的第 4 代 iPod Touch 上,NSFileSystemFreeSize 仍然报告了大约 200 MB 的数据。我在调试器中打印出整个 NSDictionary 的内容......虽然 NSFileSystemSize 是正确的......有人有这个问题的解决方案吗?
  • @Zennichimaro:你的问题解决了吗?我也面临同样的问题,当我检查 iPad 中的可用空间时,会额外获得 0.2 GB。 iPad 显示 24.1 GB 可用空间,但在代码中显示 24.3 GB。
  • @Diejmon 你不能向 NSNumber 询问这种类型的整数大小。这就是为什么对于这些​​事情我更喜欢一个已知位大小的单位。虽然从技术上讲我同意你的说法,但我已经有足够的警告来处理使用 NSInteger 和格式化字符串!在我和你的一生中,64 位肯定足够了。
【解决方案4】:

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

【讨论】:

【解决方案5】:

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

【讨论】:

    【解决方案6】:

    如果您希望使用 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:为安全起见已更新,using Martin R's answer.
    编辑 3:为 Swift 2.0 更新(dgellow

    【讨论】:

    • 我试图使用这个答案,但它不会在 GM 下编译([NSObject : AnyObject]? 没有名为“下标”的成员)。我认为这是由于here 提出的问题,但我不明白如何在这种情况下使该答案起作用。非常感谢任何帮助。
    • 我现在更新了在 Swift 1.0 上工作的答案。因为 attributesOfFileSystemForPath 返回 [NSObject : AnyObject]?你需要转换到 NSDictionary 吗?因为它可能是 nil 然后打开字典以对其下标。 (这有点不安全,所以我稍后会用更安全的解决方案更新答案。)
    • 感谢您的更新。事实证明,在您回复之前大约一个小时,我已经将这个问题表述为一个新问题here。现在有一个答案,但是由于这种处理选项的方法对我来说有点不透明,我很乐意在您方便的时候看到另一种方法。向你姐姐瑞秋问好。
    • Bryan,我建议您回答问题的第一个答案,因为它是安全性和清晰度的良好结合。我不确定我能否给出比那个更好的答案。选项一开始可能会让人感到困惑,我强烈建议阅读Swift manuals section on optionals 它非常好。
    • 非常感谢,我会再次查看该手册,并且我也发现了一些很好的 SO 问题。布莱恩
    【解决方案7】:

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

    当我使用上面的代码时:

    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 应用程序会完全显示给我的数字。

    【讨论】:

    • 也许 File 仅适用于 MAC 文件而不适用于 iOS?
    • 它的字节数乘以 1000(KB 然后 MB 然后 GB)而不是 1024。
    【解决方案8】:

    我编写了一个类来使用 Swift 获取可用/已用内存。 演示地址: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
            }
        }
    
    }
    

    演示

    【讨论】:

    • 你知道为什么会有 MBFormatter 吗?它没有在任何地方使用。
    • MBFormatter 是将任意值转换为 MB 值的函数。我没有将它用于演示项目。但我需要其他项目。
    • 这很适合放入 FileManager 扩展。
    • iTunes 显示 18.99 GB 免费,但当我使用所述方法时,我得到 13.41 GB。有人知道我想念什么吗?
    • @CuongLam 展开错误不会被抛出,也不会被 do/catch 捕获。应编写示例源代码以正确处理错误。 stackoverflow.com/questions/34628999/…
    【解决方案9】:

    这是我的答案以及为什么它更好。

    答案(斯威夫特):

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

    为什么更好:

    • 利用 Cocoa 的内置库NSByteCountFormatter,这意味着无需从字节到千兆字节的疯狂手动计算。 Apple 会为您做到这一点!
    • 易于翻译:NSByteCountFormatter 为您完成这项工作。例如。当设备的语言设置为英语时,字符串的大小为 248.8 MB,但设置为法语时,字符串的大小为 248,8 Mo,其他语言的字符串等等。
    • 出现错误时会给出默认值。

    【讨论】:

    • @JuanBoero 发布在 Swift 3.1 中(终于)!
    【解决方案10】:

    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
    
    }
    

    【讨论】:

      【解决方案11】:

      对于 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.
      

      【讨论】:

        【解决方案12】:

        我知道这篇文章有点老了,但我认为这个答案可以帮助别人。如果您想知道设备上已用/可用/总磁盘空间,您可以使用Luminous。它是用 Swift 编写的。你只需要打电话:

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

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

        【讨论】:

          【解决方案13】:

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

          【讨论】:

          • 为什么返回的信息多于 iPhone 的可用磁盘空间信息。当 iPhone 的设置菜单显示 998MB 时,返回 1.2 GB
          【解决方案14】:

          上述代码的 Swift 实现:-

          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+ 中。这只是上述答案的快速实施。对我来说,接受的答案不起作用。

          【讨论】:

            【解决方案15】:

            使用新的准确 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
                    }
                }
            }
            

            【讨论】:

            • 您的屏幕截图中的“机会主义使用”来自哪里?
            • 找到了,volumeAvailableCapacityForOpportunisticUsageKey
            • 是的 rshev,volumeAvailableCapacityForOpportunisticUsageKey 在我的屏幕截图上得到“机会使用”
            • 查看可用存储大小我应该使用NSHomeDirectory()NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true) 查询。使用这两者有什么区别吗?
            【解决方案16】:

            如果您想节省时间,请使用以下 CocoaPod 库。我没有使用它,但似乎它应该可以工作。

            https://cocoapods.org/pods/SystemServices

            【讨论】:

              【解决方案17】:

              您可以使用 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()
              

              【讨论】:

              • 不要使用! 而是将guard 放到安全的typecastingnil 检查。
              • 感谢您的 cmets @TheTiger。
              【解决方案18】:

              这里是 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)")
              }
              

              【讨论】:

                猜你喜欢
                • 2018-07-09
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-01-23
                • 2019-12-12
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多