views:

543

answers:

5

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

A: 

I don't know Objective-C or the iPhone SDK, but the principle's the same for any hierarchical file system. It's a pretty simple recursive function. In pseudocode:

function CalcFolderSize(folderName): integer
  fileList = GetListOfAllFilesInFolder(folderName)
  totalSize = 0
  for each entry in fileList
    totalSize = totalSize + fileSize(entry)
  folderList = GetListOfAllFoldersInFolder(foldername)
  for each entry in folderList
    totalSize = totalSize + CalcFolderSize(entry)
end function
Mason Wheeler
Yep, I know that, I'm specifically talking about the iPhone SDK and if there is a function of a piece of code that I don't know about that will give me the folder size in bytes.I'd rather not loop through a folder if I don't have to :)
iphone_developer
A: 

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;
}
Alex Reynolds
+1  A: 

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,

iphone_developer
There are two complications I can think of to explain the disparity: 1024 bytes is equivalent to 1 KB (or KiB? depends on who you ask) and also "block size", where a file's bytes can take up multiples of larger chunks of disk space — this is a file system level optimization that is dependent on the disk formatting and disk capacity. A 1024 byte file could actually take up a whole 16 KB block, for example, and thus be listed as a 16 KB file although it only uses 1024 bytes.
Alex Reynolds
Thanks for sharing your code, btw.
Alex Reynolds
A: 

This is the way I did it:

NSString *filepath1 = [self dataFilePath];
NSFileManager* fileManager = [NSFileManager defaultManager];
NSDictionary* attributes = [fileManager fileAttributesAtPath:filepath1 
                                                traverseLink:NO];

NSNumber* fileSize = [attributes objectForKey:NSFileSize];
int e = [fileSize intValue]; //Size in bytes

And here's dataFilePath:

-(NSString *)dataFilePath
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
return [documentsDirectory stringByAppendingPathComponent:kFilename];
}
Matt S.
A: 

Hey although this is not related(sorry I dont know how else to ask you!!),did you just stop saving images when the size of your folder reached MAX or did you delete some images to clear up the cache.

Since from the file we can know what the dates are when these images were saved we can delete 10 random images from intermediate dates.

Of course the optimal solution would be keep a plist file and write down the frequency of access of each image to get the image with the lowest frequency and delete it.But that would introduce innecessary overhead and a little more work(I'm lazy!!)

what do you think??

samyzee