Calculate the size of a folder

0 votes
asked Feb 2, 2010 by joseph-carney

Just a quick one...

I'm creating a folder to cache images inside Documents with my iPhone App. I want to be able to keep the size of this folder down to 1MB, so I need to to check the size in bytes of my folder.

I have code to calculate the size of file, but I need the size of the folder.

What would be the best way to do this? Will I need to loop through each file?

Cheers

14 Answers

0 votes
answered Jan 3, 2010 by alex-reynolds

Something like the following should help get you started. You'll need to modify _documentsDirectory to your specific folder, though:

- (unsigned long long int) documentsFolderSize {
    NSFileManager *_manager = [NSFileManager defaultManager];
    NSArray *_documentPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *_documentsDirectory = [_documentPaths objectAtIndex:0];   
    NSArray *_documentsFileList;
    NSEnumerator *_documentsEnumerator;
    NSString *_documentFilePath;
    unsigned long long int _documentsFolderSize = 0;

    _documentsFileList = [_manager subpathsAtPath:_documentsDirectory];
    _documentsEnumerator = [_documentsFileList objectEnumerator];
    while (_documentFilePath = [_documentsEnumerator nextObject]) {
        NSDictionary *_documentFileAttributes = [_manager fileAttributesAtPath:[_documentsDirectory stringByAppendingPathComponent:_documentFilePath] traverseLink:YES];
        _documentsFolderSize += [_documentFileAttributes fileSize];
    }

    return _documentsFolderSize;
}
0 votes
answered Feb 3, 2010 by joseph-carney

Cheers for that Alex, you helped a lot, have now written the following function which does the trick...

- (unsigned long long int)folderSize:(NSString *)folderPath {
    NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
    NSString *fileName;
    unsigned long long int fileSize = 0;

    while (fileName = [filesEnumerator nextObject]) {
        NSDictionary *fileDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
        fileSize += [fileDictionary fileSize];
    }

    return fileSize;
}

It is coming up with the exact number of bytes as Finder does.

As an aside, Finder returns two numbers. One is the size on the disk and the other is the actual number of bytes.

For example, when I run this code on one of my folders, it comes back in the code with a 'fileSize' of 130398. When I check in Finder, it says the size is 201KB on disk (130,398 bytes).

Am a little unsure of what to go with here (201KB or 130,398 bytes) as the actual size. For now, I'll go on the safe side and cut my limit in half until I find out what this means exactly...

If anyone can add any more information to these differing numbers I'd appreciate it.

Cheers,

0 votes
answered Jan 15, 2011 by wrightscs

I used this code to get the directory size of 2 directories, if one directory didnt exist, it would show Zero KB. Otherwise, the second half of the code will display the folder size along with the KB, MB, GB, respectively, and it will also display it in a clean format: 10.02 MB.

Try this something like this:

- (unsigned long long int)folderSize:(NSString *)folderPath {
    NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
    NSString *fileName;
    unsigned long long int fileSize = 0;

    while (fileName = [filesEnumerator nextObject]) {
        NSDictionary *fileDictionary = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:fileName] traverseLink:YES];
        fileSize += [fileDictionary fileSize];
    } 

    return fileSize;
}

-(NSString *)getMPSize
{
    NSString*sizeTypeW = @"bytes";
    int app = [self folderSize:@"/PathToTheFolderYouWantTheSizeOf/"];
    NSFileManager *manager = [NSFileManager defaultManager];
    if([manager fileExistsAtPath:@"/AnotherFolder/"] == YES){

        int working = [self folderSize:@"/AnotherFolder/"];
        if(working<1){
            return @"Size: Zero KB";
        }else{
            if (working > 1024)
            {
                //Kilobytes
                working = working / 1024;

                sizeTypeW = @" KB";
            }

            if (working > 1024)
            {
                //Megabytes
                working = working / 1024;

                sizeTypeW = @" MB";
            }

            if (working > 1024)
            {
                //Gigabytes
                working = working / 1024;

                sizeTypeW = @" GB";
            }

            return [NSString stringWithFormat:@"App: %i MB, Working: %i %@ ",app/1024/1024, working,sizeTypeW];
        }

    }else{
        return [NSString stringWithFormat:@"App: %i MB, Working: Zero KB",app/1024/1024];
    }
    [manager release];
}
0 votes
answered Jan 2, 2012 by prakash-raj

if we want to get the size of any file then here is a method, where we only need to pass path of that file.

- (unsigned long long int) fileSizeAt:(NSString *)path {
    NSFileManager *_manager = [NSFileManager defaultManager];
    return [[_manager fileAttributesAtPath:path traverseLink:YES] fileSize];
}
0 votes
answered Jan 23, 2012 by clay-bridges

Not sure if this helps anyone, but I wanted to relate some of my findings (some inspired by @zneak's comment above).

  1. I could not find any shortcuts using NSDirectoryEnumerator to avoid enumerating through files to get the total contained size of a directory.

  2. For my tests, using -[NSFileManager subpathsOfDirectoryAtPath:path error:nil] was faster than using -[NSFileManager enumeratorAtPath:path]. This looks to me like it might be a classic time/space tradeoff, as subPaths... creates an NSArray on which it then iterates, where enumerator... might not.

Some background on #1. Assuming:

NSFileManager *fileMan = [NSFileManager defaultManager];
NSString *dirPath = @"/"; // references some directory

Then

[fileMan enumeratorAtPath:dirPath] fileAttributes]

returns nil. The correct attribute accessor is directoryAttributes, but

[fileMan enumeratorAtPath:dirPath] directoryAttributes] fileSize]

returns the size of the directory information, not the recursive sum of the sizes of all contained files (a lá ⌘-I in Finder).

0 votes
answered Jan 28, 2012 by ndoc

In iOS 5 the method -filesAttributesAtPath: is deprecated. Here is the version of the first code posted with the new method:

- (unsigned long long int)folderSize:(NSString *)folderPath {
    NSArray *filesArray = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *filesEnumerator = [filesArray objectEnumerator];
    NSString *fileName;
    unsigned long long int fileSize = 0;

    while (fileName = [filesEnumerator nextObject]) {
        NSDictionary *fileDictionary = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:fileName] error:nil];
        fileSize += [fileDictionary fileSize];
    }

    return fileSize;
}
0 votes
answered Jan 9, 2013 by zyios

I think use Unix C method is better for performance.

+ (long long) folderSizeAtPath: (const char*)folderPath {
  long long folderSize = 0;
  DIR* dir = opendir(folderPath);
  if (dir == NULL) return 0;
  struct dirent* child;
  while ((child = readdir(dir))!=NULL) {
    if (child->d_type == DT_DIR
        && child->d_name[0] == '.'
        && (child->d_name[1] == 0 // ignore .
            ||
            (child->d_name[1] == '.' && child->d_name[2] == 0) // ignore dir ..
           ))
      continue;

    int folderPathLength = strlen(folderPath);
    char childPath[1024]; // child 
    stpcpy(childPath, folderPath);
    if (folderPath[folderPathLength-1] != '/'){
      childPath[folderPathLength] = '/';
      folderPathLength++;
    }
    stpcpy(childPath+folderPathLength, child->d_name);
    childPath[folderPathLength + child->d_namlen] = 0;
    if (child->d_type == DT_DIR){ // directory
      folderSize += [self _folderSizeAtPath:childPath]; // 
      // add folder size
      struct stat st;
      if (lstat(childPath, &st) == 0)
        folderSize += st.st_size;
    } else if (child->d_type == DT_REG || child->d_type == DT_LNK){ // file or link
      struct stat st;
      if (lstat(childPath, &st) == 0)
        folderSize += st.st_size;
    }
  }
  return folderSize;
}
0 votes
answered Jan 22, 2013 by thetiger

This is how to get folder and file size in MB, KB and GB ---

1. Folder Size -

-(NSString *)sizeOfFolder:(NSString *)folderPath
{
    NSArray *contents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:nil];
    NSEnumerator *contentsEnumurator = [contents objectEnumerator];

    NSString *file;
    unsigned long long int folderSize = 0;

    while (file = [contentsEnumurator nextObject]) {
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:file] error:nil];
        folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
    }

    //This line will give you formatted size from bytes ....
    NSString *folderSizeStr = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleFile];
    return folderSizeStr;
}

Note: In case of sub folders please use subpathsOfDirectoryAtPath: instead of contentsOfDirectoryAtPath:

2. File Size -

-(NSString *)sizeOfFile:(NSString *)filePath
{
    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
    NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] integerValue];
    NSString *fileSizeStr = [NSByteCountFormatter stringFromByteCount:fileSize countStyle:NSByteCountFormatterCountStyleFile];
    return fileSizeStr;
}
0 votes
answered Jan 25, 2013 by stoto

I cleaned up a bit the first answer's implementation before using it, so it no longer throws deprecated warnings + using fast enumeration.

/**
 *  Calculates the size of a folder.
 *
 *  @param  folderPath  The path of the folder
 *
 *  @return folder size in bytes
 */
- (unsigned long long int)folderSize:(NSString *)folderPath {
    NSFileManager *fm = [NSFileManager defaultManager];
    NSArray *filesArray = [fm subpathsOfDirectoryAtPath:folderPath error:nil];
    unsigned long long int fileSize = 0;

    NSError *error;
    for(NSString *fileName in filesArray) {
        error = nil;
        NSDictionary *fileDictionary = [fm attributesOfItemAtPath:[folderPath     stringByAppendingPathComponent:fileName] error:&error];
        if (!error) {
            fileSize += [fileDictionary fileSize];
        }else{
            NSLog(@"ERROR: %@", error);
        }
    }

    return fileSize;
}
0 votes
answered Jan 1, 2014 by icodebuster

Updated Method using enumeration block

Calculate Folder Size with only files

- (NSString *)sizeOfFolder:(NSString *)folderPath {
    NSArray *folderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:folderPath error:nil];
    __block unsigned long long int folderSize = 0;

    [folderContents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:obj] error:nil];
        folderSize += [[fileAttributes objectForKey:NSFileSize] intValue];
    }];
    NSString *folderSizeStr = [NSByteCountFormatter stringFromByteCount:folderSize countStyle:NSByteCountFormatterCountStyleFile];
    return folderSizeStr;
}

Calculate Folder Size with other sub directories in the folder

 NSArray *folderContents = [[NSFileManager defaultManager] subpathsOfDirectoryAtPath:folderPath error:nil];

Get File Size

- (NSString *)sizeOfFile:(NSString *)filePath {
    NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:nil];
    NSInteger fileSize = [[fileAttributes objectForKey:NSFileSize] integerValue];
    NSString *fileSizeString = [NSByteCountFormatter stringFromByteCount:fileSize countStyle:NSByteCountFormatterCountStyleFile];
    return fileSizeString;
}
Welcome to Q&A, where you can ask questions and receive answers from other members of the community.
Website Online Counter

...