How can I calculate the size of a folder?

tl;dr

All the other answers are off 🙂

Problem

I’d like to add my two cents to this old question as there seem to be many answers that are all very similar but yield results that are in some cases very unprecise.

To understand why we first have to define what the size of a folder is. In my understanding (and probably the one of the OP) it is the amount of bytes that the directory including all of its contents uses on the volume. Or, put in another way:

It is the space becoming available if the directory would be completely removed.

I’m aware that this definition is not the only valid way to interpret the question but I do think it’s what most use cases boil down to.

Error

The existing answers all take a very simple approach: Traverse the directory contents, adding up the sizes of (regular) files. This does not take a couple of subtleties into account.

  • The space used on the volume increments in blocks, not in bytes. Even a one byte file uses at least one block.
  • Files carry around meta data (like any number of extended attributes). This data must go somewhere.
  • HFS deploys file system compression to actually store the file using less bytes then its real length.

Solution

All of these reasons make the existing answers produce unprecise results. So I’m proposing this extension on NSFileManager (code on github due to length: Swift 4, Objective C) to remedy the problem. It’s also quite a bit faster, especially with directories containing a lot of files.

The core of the solution is to use NSURL‘s NSURLTotalFileAllocatedSizeKey or NSURLFileAllocatedSizeKey properies to retrieve file sizes.

Test

I’ve also set up a simple iOS test project, demonstrating the differences between the solutions. It shows how utterly wrong the results can be in some scenarios.

In the test I create a directory containing 100 small files (ranging from 0 to 800 bytes). The folderSize: method copied from some other answer calculates a total of 21 kB while my allocatedSize method yields 401 kB.

Proof

I made sure that the results of allocatedSize are closer to the correct value by calculating the difference of the available bytes on the volume before and after deleting the test directory. In my tests the difference was always exactly equal to the result of allocatedSize.

Please see Rob Napier’s comment to understand that there’s still room for improvement.

Performance

But there’s another advantage: When calculating the size of a directory with 1000 files, on my iPhone 6 the folderSize: method takes about 250 ms while allocatedSize traverses the same hierarchy in 35 ms.

This is probably due to using NSFileManager‘s new(ish) enumeratorAtURL:includingPropertiesForKeys:options:errorHandler: API to traverse the hierachy. This method let’s you specify prefetched properties for the items to be iterated, resulting in less io.

Results

Test `folderSize` (100 test files)
    size: 21 KB (21.368 bytes)
    time: 0.055 s
    actual bytes: 401 KB (401.408 bytes)

Test `allocatedSize` (100 test files)
    size: 401 KB (401.408 bytes)
    time: 0.048 s
    actual bytes: 401 KB (401.408 bytes)

Test `folderSize` (1000 test files)
    size: 2 MB (2.013.068 bytes)
    time: 0.263 s
    actual bytes: 4,1 MB (4.087.808 bytes)

Test `allocatedSize` (1000 test files)
    size: 4,1 MB (4.087.808 bytes)
    time: 0.034 s
    actual bytes: 4,1 MB (4.087.808 bytes)

Leave a Comment