How to get file size using FileManager + formatting

Learn how to get file size URL and also how to format it to human-readable string by special formatter.

If you need to get file size programmatically in Swift using the file's URL then it is just a matter of a few lines of code. Let's see how. All we need is an URL for the file in question.

Getting file size with FileManager

We are going to use method attributesOfItem available on the FileManager. As the naming suggests this will return attributes for item. In our case a file. We need to supply a path to the file which we can get from the URL.

if let fileAttributes = try? FileManager.default.attributesOfItem(atPath: fileURL.path) {
}

This method can throw so we are using try? to safely get the attributes or nil in case of an issue. In this case that would most likely be incorrect path or for some reason unreadable file.

fileAttributes is a dictionary and we can get size like so:

if let bytes = fileAttributes[.size] as? Int64 {
}

The whole thing is in bytes meaning it is not very human-readable number.

Extension

We can also create handy extension to abstract away all this code. Feel free to use it in your project 🙂

extension FileManager {
    func sizeOfFile(atPath path: String) -> Int64? {
        guard let attrs = try? attributesOfItem(atPath: path) else {
            return nil
        }

        return attrs[.size] as? Int64
    }
}

It depends whether you need to use file size internally (to maybe estimate upload time etc) or if you want to present the result to the user.

In the latter case do not display number of bytes but instead convert it to readable number.

Displaying readable size with ByteCountFormatter

Swift has really cool and useful class called ByteCountFormatter which can format byte count to readable string.

Let's use it to format our file size.

ByteCountFormatter usage

let bcf = ByteCountFormatter()
bcf.allowedUnits = [.useMB]
bcf.countStyle = .file
let string = bcf.string(fromByteCount: bytes)

We first create instance, then set allowedUnits in this case to only megabytes because we are expecting files bigger than 1 MB and smaller than 1 GB and set countStyle to .file.

Then it is just a matter of getting the resulting string. ByteCountFormatter will automatically append unit (in this case "MB") so we don't have to do any post-formatting. 👏

The result will be something like "24,4 MB" with either "," or "." as a separator depending on the user's locale settings.

For frequent usage I would recommend creating something like a static instance to avoid creating instances over and over again and have centralized configuration.

private let fileByteCountFormatter: ByteCountFormatter = {
    let bcf = ByteCountFormatter()
    bcf.allowedUnits = [.useMB]
    bcf.countStyle = .file
    return bcf
}()

And that is it! For more options you can check the official documentation.

Thanks for reading!

Uses: Xcode 12 & Swift 5.3

Filip Němeček profile photo

WRITTEN BY

Filip Němeček @nemecek_f

iOS blogger and developer with interest in Python/Django. Telling other devs' stories with iOS Chat.