我正在寻找一种更好的方法来以编程方式检测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;
}
我是否正确使用上述代码段?或者是否有更好的方法来了解总可用/可用磁盘空间
我要检测总可用磁盘空间,因为我们要阻止我们的应用程序在低磁盘空间场景中执行同步。
答案 0 :(得分:151)
更新:由于在此答案之后已经过了很多时间并且添加了新的方法/ 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显示的大小。
答案 1 :(得分:58)
使用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。
答案 2 :(得分:26)
如果您需要带有大小的格式化字符串,可以查看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;
}
答案 3 :(得分:24)
我已经编写了一个类来使用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
}
}
}
演示
答案 4 :(得分:13)
不要使用'unsigned',它只有32位,它会超过4GB,这比典型的iPad / iPhone可用空间要少。使用unsigned long long(或uint64_t),并使用unsignedLongLongValue将值从NSNumber中检索为64位int。
答案 5 :(得分:12)
如果您希望使用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)
答案 6 :(得分: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;
}
为什么它更好:
NSByteCountFormatter
,意味着没有从字节到千兆字节的疯狂手动计算。 Apple为您做到这一点!答案 7 :(得分:7)
重要澄清(至少对我而言)。如果我将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];
countStyle NSByteCountFormatterCountStyleFile 告诉我:17,41 GB
countStyle NSByteCountFormatterCountStyleBinary 告诉我:16,22 GB
16,22 GB ( NSByteCountFormatterCountStyleBinary )当我将iPod连接到Mac时,iTunes App显示的数字正确。
答案 8 :(得分:4)
您可以使用 Swift 4 和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"
}
}
样本用法:
UIDevice.current.totalDiskSpaceInBytes()
UIDevice.current.totalDiskSpace()
UIDevice.current.freeDiskSpaceInBytes()
UIDevice.current.freeDiskSpace()
UIDevice.current.usedDiskSpaceInBytes()
UIDevice.current.usedDiskSpace()
答案 9 :(得分:3)
对于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];
答案 10 :(得分:3)
使用新的准确API进行更新,以获得iOS11中可用磁盘的可用大小。 以下是新API资源键的说明:
@RunWith(RobolectricTestRunner.class)
public class TestClass {
@Test
public void testMethod() {
Uri uri = Uri.parse("anyString")
//then do what you want, just like normal coding
}
}
我比较了关键" FileAttributeKey.systemFreeSize "的结果。和键" URLResourceKey.volumeAvailableCapacityForImportantUsageKey "并发现结果返回表格" volumeAvailableCapacityForImportantUsageKey "与UI上显示的可用存储完全匹配。 这是快速实施:
#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
答案 11 :(得分:2)
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)")
}
答案 12 :(得分:2)
Following code is Swift 3.0 version implementation of the answer previously provided by 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
}
答案 13 :(得分:1)
我知道这篇文章有点陈旧,但我认为这个答案可以帮到某些人。如果您想知道设备上的已用/可用/总磁盘空间,可以使用Luminous。它是用Swift编写的。你只需要打电话:
Luminous.System.Disk.freeSpace()
Luminous.System.Disk.usedSpace()
或
Luminous.System.Disk.freeSpaceInBytes()
Luminous.System.Disk.usedSpaceInBytes()
答案 14 :(得分:1)
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.
答案 15 :(得分:0)
快速实现上述代码: -
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 +中。它只是迅速实现上面显示的答案。对我来说,接受的答案并不奏效。
答案 16 :(得分:0)
如果您想节省时间,请使用以下CocoaPod库。我没有使用它,但似乎它应该有用。
答案 17 :(得分:0)
ChrisJF 回答:
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
}