views:

26

answers:

1

Hello,

I've written methods that help me get the size of files/folders and translate the result in a human readable string. Problem is, when this size exceeds about 2.1GB, the number returned changes to a random negative number, like "-4324234423 bytes", which is useless.

Things I've found out about & done about this issue:

  • 32GB is limited to this size, so I compile in 64bit instead.
  • I've tried using both CGFloat and NSUInteger, but both still return the same value as NSInteger.

I am quite frustrated, I don't know what I am missing. Here are my methods:

- (NSString *)stringFromFileSize:(int)theSize
{
 CGFloat floatSize = theSize;
 if (theSize<1023)
  return([NSString stringWithFormat:@"%i bytes",theSize]);
 floatSize = floatSize / 1024;
 if (floatSize<1023)
  return([NSString stringWithFormat:@"%1.1f KB",floatSize]);
 floatSize = floatSize / 1024;
 if (floatSize<1023)
  return([NSString stringWithFormat:@"%1.2f MB",floatSize]);
 floatSize = floatSize / 1024;

 return([NSString stringWithFormat:@"%1.2f GB",floatSize]);
}

- (NSUInteger)sizeOfFile:(NSString *)path
{
 NSDictionary *fattrib = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
 NSUInteger fileSize = (NSUInteger)[fattrib fileSize];
 return fileSize;
}

- (NSUInteger)sizeOfFolder:(NSString*)folderPath
{
 NSArray *contents;
 NSEnumerator *enumerator;
 NSString *path;
 contents = [[NSFileManager defaultManager] subpathsAtPath:folderPath];
 enumerator = [contents objectEnumerator];
 NSUInteger fileSizeInt = 0;
 while (path = [enumerator nextObject]) {
  NSDictionary *fattrib = [[NSFileManager defaultManager] attributesOfItemAtPath:[folderPath stringByAppendingPathComponent:path] error:nil];
  fileSizeInt +=[fattrib fileSize];
 }
 return fileSizeInt;
}

What am I missing? Is NSFileManager returning a 32bit value? What's causing this?

Thanks!

+1  A: 

Alas, nearly all systems have "int" being 32-bit, even if you "compile for 64-bit". (Windows, Mac and Linux work this way). See http://en.wikipedia.org/wiki/64-bit#Specific_C-language_data_models.

You can either pass long to your stringFromFileSize method, or you can pass a NSUInteger.

Adrian Smith
i thought that CGFloat is 64bit too?
David Schiefer
The trouble is, that by the time you create the "CGFloat" in "stringFromFileSize", the value has already been an "int" (the parameter to the function), and that value must be wrong if you're dealing with large values, as ints cannot store values larger than 2G if they're signed 32-bit.
Adrian Smith
ah I see! That's true...
David Schiefer
Problem solved.Can't believe I have missed that, thanks very much! +1 for a great answer!
David Schiefer
No problem, I literally sat for hours once staring at exactly the same problem, so I'm glad I could help! The first OS I used for professional work, "tru64", it's so old now that it's been discontinued, used 64-bit for int. It didn't even occur to me that a modern OS like Linux, Mac, Windows would just use 32-bit int on their 64-bit versions .... :(
Adrian Smith