Easy way to get size of folder (ObjC/Cocoa)?
Solution 1
I needed to do this today myself, and I've found that the code in this post on the Cocoa-dev list is super fast and matches what Finder says to the byte. (don't forget to OR in the kFSCatInfoRsrcSizes flag so you get resource fork sizes, too!)
If you need more explanation on how to use it, just leave a comment and I'll edit this post. =)
Solution 2
The documentation for fileSize
states it does not include the size of a resource fork. You may need to use the Carbon File Manager API to reliably calculate directory sizes.
Solution 3
I just wanted to second Dave DeLong's suggestion about the post on Cocoa-dev, but add a cautionary note to be sure to read all the posts in the thread. There is one by Rosyna that's particularly worth noting. In my case I followed that advice (changing max items per fetch to 40) and saw a speed jump as well as the end to a nasty crashing bug.
Solution 4
hope this will help
- (unsigned long long) fastFolderSizeAtFSRef:(NSString *)theFilePath
{
unsigned long long totalSize = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isdirectory;
NSError *error;
if ([fileManager fileExistsAtPath:theFilePath])
{
NSMutableArray * directoryContents = [[fileManager contentsOfDirectoryAtPath:theFilePath error:&error] mutableCopy];
for (NSString *fileName in directoryContents)
{
if (([fileName rangeOfString:@".DS_Store"].location != NSNotFound) )
continue;
NSString *path = [theFilePath stringByAppendingPathComponent:fileName];
if([fileManager fileExistsAtPath:path isDirectory:&isdirectory] && isdirectory )
{
totalSize = totalSize + [self fastFolderSizeAtFSRef:path];
}
else
{
unsigned long long fileSize = [[fileManager attributesOfItemAtPath:path error:&error] fileSize];
totalSize = totalSize + fileSize;
}
}
}
return totalSize;
}
Solution 5
This code is as extension(category) to the NSFileManager class. It sums the sizes of all folder content. Note that error treatment could be enhanced.
@interface NSFileManager(Util)
- (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error;
@end
@implementation NSFileManager(Util)
- (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error
{
NSArray * contents;
unsigned long long size = 0;
NSEnumerator * enumerator;
NSString * path;
BOOL isDirectory;
// Determine Paths to Add
if ([self fileExistsAtPath:source isDirectory:&isDirectory] && isDirectory)
{
contents = [self subpathsAtPath:source];
}
else
{
contents = [NSArray array];
}
// Add Size Of All Paths
enumerator = [contents objectEnumerator];
while (path = [enumerator nextObject])
{
NSDictionary * fattrs = [self attributesOfItemAtPath: [ source stringByAppendingPathComponent:path ] error:error];
size += [[fattrs objectForKey:NSFileSize] unsignedLongLongValue];
}
// Return Total Size in Bytes
return [ NSNumber numberWithUnsignedLongLong:size];
}
@end
indragie
iOS and Mac Developer. I'm working on Flamingo for Mac and previously built Sonora.
Updated on June 09, 2022Comments
-
indragie almost 2 years
Right now I'm using this code to get the size of a folder:
NSArray *contents; NSEnumerator *enumerator; NSString *path; contents = [[NSFileManager defaultManager] subpathsAtPath:folderPath]; enumerator = [contents objectEnumerator]; while (path = [enumerator nextObject]) { NSDictionary *fattrib = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:path] traverseLink:YES]; fileSize +=[fattrib fileSize]; } [contents release]; [path release];
The problem is that its highly innacurate. It either adds a few megabytes or deducts a few megabytes from the actual size. For example I got the file size of an .app bundle and this method reported 16.2MB, whereas the actual thing is 15.8.
What's the best way to get the size of a folder?
Thanks
-
kperryua over 14 yearsAh yes, that's another possibility. I forgot about that.
-
Quinn Taylor over 14 yearsMight be better to add this as a comment to his answer so they stay related even as their positions on the page change.
-
indragie over 14 yearsI'm having problems with Dave DeLong's method. I use this code to convert my NSString into an FSRef: FSRef f; OSStatus os_status = FSPathMakeRef((const UInt8 *)[filePath fileSystemRepresentation], &f, NULL); if (os_status == noErr) { NSLog(@"Success"); } And then I try to run the method: [self fastFolderSizeAtFSRef:f]; However I get the error "incompatible type for argument 1 of 'fastFolderSize'" Any ideas ? Thanks
-
indragie over 14 yearsThanks, what's a good way to convert an NSString containing a path to an FSRef? Thanks
-
Dave DeLong over 14 yearsJust answered your question. =)
-
Dave DeLong over 14 yearswhile this will certainly work, you have the performance hit of creating another process (which can be pretty expensive), or using
NSFileManager
, which doesn't include resource forks when calculating sizes. -
Igor about 7 years@Dave, this link is broken, could you update it or place code to answer?
-
Dave DeLong about 7 years@Igor fixed w/ an archive.org link
-
Igor about 7 yearsThanks for fast reply!
-
Igor about 7 yearsDo you think it's still up to date solution?
-
Dave DeLong about 7 yearsFundamentally, probably. It's possible portions of the api have been superseded in the past 12 years though ;)