9

I suppose I'd like to be able to find out for any storage, not just the system disk, but that's most important.

zekel
  • 8,396
  • 10
  • 61
  • 94

7 Answers7

13

Use -[NSFileManager attributesOfFileSystemForPath:error:]

DrMickeyLauer
  • 3,807
  • 3
  • 26
  • 59
Azeem.Butt
  • 6,017
  • 1
  • 24
  • 22
  • -[NSFileManager attributesOfFileSystemForPath:error:] doesn't return a dict with the key NSFileSystemFreeSize in it. – zekel Oct 28 '09 at 21:26
  • 1
    Whoops, you were right. Looks like I tried that on the class, not the instance. – zekel Jan 20 '10 at 22:06
  • Hi, what if one of the sub-folders in the path points to another filesystem, does the NSFileManager knows to ignore it when retrieving the attributes ? – Zohar81 Jan 18 '18 at 10:12
11

I use this:

NSDictionary* fileAttributes = [[NSFileManager defaultManager] attributesOfFileSystemForPath:@"/"
                                                                                   error:&error];
unsigned long long freeSpace = [[fileAttributes objectForKey:NSFileSystemFreeSize] longLongValue];
NSLog(@"free disk space: %dGB", (int)(freeSpace / 1073741824));
Avi Cohen
  • 111
  • 1
  • 4
  • Perfect code! Works like charm! Thanks a lot for sharing. : ) – zeFree Mar 01 '13 at 15:51
  • My 2 cents - 1) use a NSString containing the path to a volume in place of @"/" to view information for other volumes. 2) it'd be better if we use unsignedLongLongValue instead of longLongValue. – zeFree Mar 02 '13 at 08:27
10

EDIT fileSystemAttributesAtPath: is deprecated, use attributesOfFileSystemForPath:error: as NSD suggested. I made a mistake when I thought it didn't work.

// this works
NSError *error = nil;
NSDictionary *attr = [NSFM attributesOfFileSystemForPath:@"/" error:&error];
if (!error) {
    double bytesFree = [[attr objectForKey:NSFileSystemFreeSize] doubleValue];
}

I tried this, attributesOfItemAtPath:error but the dict returned didn't seem to have the NSFileSystemFreeNodes key.

NSFileManager *fm = [NSFileManager defaultManager];
NSError *error = nil;
NSDictionary *attr = [fm attributesOfItemAtPath:@"/" error:&error];
if (!error) {
    NSLog(@"Attr: %@", attr);
}

2009-10-28 17:21:11.936 MyApp[33149:a0b] Attr: {
    NSFileCreationDate = "2009-08-28 15:37:03 -0400";
    NSFileExtensionHidden = 0;
    NSFileGroupOwnerAccountID = 80;
    NSFileGroupOwnerAccountName = admin;
    NSFileModificationDate = "2009-10-28 15:22:15 -0400";
    NSFileOwnerAccountID = 0;
    NSFileOwnerAccountName = root;
    NSFilePosixPermissions = 1021;
    NSFileReferenceCount = 40;
    NSFileSize = 1428;
    NSFileSystemFileNumber = 2;
    NSFileSystemNumber = 234881026;
    NSFileType = NSFileTypeDirectory;
}

After looking around a bit, it seems like fileSystemAttributesAtPath: is the method that returns it. Weird.

NSFileManager *fm = [NSFileManager defaultManager];
NSDictionary *attr = [fm fileSystemAttributesAtPath:@"/"]; 
NSLog(@"Attr: %@", attr);


2009-10-28 17:24:07.993 MyApp[33283:a0b] Attr: {
    NSFileSystemFreeNodes = 5027061;
    NSFileSystemFreeSize = 20590841856;
    NSFileSystemNodes = 69697534;
    NSFileSystemNumber = 234881026;
    NSFileSystemSize = 285481107456;
}
zekel
  • 8,396
  • 10
  • 61
  • 94
  • “… use attributesOfFileSystemForPath:error: instead.” That's what NSD suggested, and you told him it didn't work. Does it work now? – Peter Hosey Jan 20 '10 at 20:47
  • Yeah, it does. Looks like I made a mistake before. – zekel Jan 20 '10 at 22:09
  • 2
    Two critiques: `error:` parameters take a pointer to a pointer to an object, `NSError **`. Thus, the correct null pointer constant is not `nil` (which would be a pointer to an object, either ` *` or `id`), it's `NULL`. More importantly, don't suppress the error return—pass a pointer to a variable there, and report the error if (and only if) the attempt to retrieve attributes fails. Silent failure is bad. – Peter Hosey Jan 21 '10 at 02:11
  • You're right on both counts. Added better handling to example code to be more instructive. – zekel Oct 28 '10 at 18:04
  • `fileSystemAttributesAtPath` is deprecated as of now. – GoodSp33d May 29 '14 at 09:52
1

Hard disk device manufacturers, use:

1GB = 1000MB

1MB = 1000 KB etc.

If you see a 8GB USB stick in Windows always shows less space than real (like 7,8 GB) because it is considered 1 GB = 1024 MB). In OSX the same USB stick is 8GB (real).

so (freeSpace / 1073741824) must be (freeSpace / 1000000000)

at least in OSX

Mike97
  • 481
  • 4
  • 18
  • To who have downvote, I invite to look at the greek vocabulary for the meaning of giga, mega etc .. – Mike97 Apr 22 '16 at 16:15
  • Your answer is good & potentially useful trivia, but it doesn't answer the question that was asked. – Michael Dautermann May 08 '16 at 19:47
  • Thanks Michael, I'm really fine with this (ie if my comment is OT), but unfortunately the answers here were simply mistaken if you consider the cocoa tag + harddrive. My answer implicitly contains a correction to the already posted code (that should be ok since is not an improvement but a correction). So if you whant find the correct space left, you have to use multiple of 1000 instead of 1024 otherwise the result will be incorrect, also because cocoa already use that. – Mike97 May 09 '16 at 11:33
1

Through swift you can get free space by using this function

func getFreeSpace() -> CGFloat {
      do {
         let fileAttributes = try NSFileManager.defaultManager().attributesOfFileSystemForPath("/")
         if let size = fileAttributes[NSFileSystemFreeSize] as? CGFloat {
            return size
         }
      } catch { }
      return 0
   }
Ahmad Ishfaq
  • 855
  • 1
  • 8
  • 10
  • 2
    Do not post multiple answers with the same content. You already posted this here http://stackoverflow.com/a/36654477/1743880. Post one good answer and flag the other as duplicate. – Tunaki Apr 15 '16 at 18:35
0

Get from this post:

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

The main difference is that you should use NSSearchPathForDirectioriesInDomains, otherwise I was getting correct value on simulator, but on the device '/' folder reference returns me something like 190MB which was not right.

Community
  • 1
  • 1
hris.to
  • 5,777
  • 3
  • 42
  • 52
0

Swift 3.0-4.0 on MacOS

I've done this for macOS and haven't had an issue. The output is in bytes so you have to divide it by the 1024.

func getHD() -> String {
    do {
        let du = try FileManager.default.attributesOfFileSystem(forPath: "/")
        if let size = du[FileAttributeKey.systemFreeSize] as? Int64 {
            return (String(size / 1024 / 1024 / 1024) + "GB")
        }
        debugPrint(du)
    }
    catch {
        debugPrint(error)
        return "Check Failed"
    }
    return "Checking..."
}

The FileManager.default.attributesOfFileSystem(forPath: "/") is just getting the various attributes available for the root directory's file system. One of those attributes happens to be the Free Disk Space.

du[FileAttributeKey.systemFreeSize] as? Int64

You access that key (key:value) and typecast it to an Int to get your free disk space.

AbsterT
  • 43
  • 4