PrettySize: a .NET library for printing human-readable file sizes

Continuing our promise to open source parts of our libraries and applications where possible, we’ve just released PrettySize, a C# and .NET library for representing file sizes in a human-readable (pretty) format. PrettySize is available for free (MIT-licensed) on GitHub and via NuGet for those that are interested, and forks, contributions, and pull-requests are actively encouraged.1

One of the best benefits of open-sourcing code is that it requires you to take a critical eye to what your code does and how it’s structured. Haphazard code interspersed throughout a dozen different files is cleaned up and re-organized in a way that can only bring benefits all around, from performance to ease-of-use, security, and future maintenance.

In this example, PrettySize went from supporting just a single notation format (2.34 KiB, for example), to supporting output using both base 10 (kilobyte, megabyte, KB, MB) and base 2 (kibibyte, mebibyte, KiB, MiB) units, with support for both abbreviated and unabridged units in the output.

Additionally, open-sourcing PrettySize also brought some performance improvements to bear (although any honest appraisal of the situation would start and end with pointing out that any sort of human-readable formatting is almost always going to be part of a much slower path in the code, namely printing to screen or similar, to an extent that actually forming the human-readable strings in question is going to be of negligible overhead), as the code went from a sequence of if (...) else ... statements like this:

if (size < 1 * (1L << 10))
    return size + " bytes";
else if (size < 10 * (1L << 10))
    return (size / (1.0 * (1L << 10))).ToString("N2") + " KiB";
else if (size < 100 * (1L << 10))
    return (size / (1.0 * (1L << 10))).ToString("N1") + " KiB";

where conversions of larger file sizes would have to go through each successive test until the matching clause was found, to a binary search performed against a sorted array of match ranges.

While the .NET Framework has included a binary tree-based SortedDictionary since .NET 2.0, it unfortunately does not support “fuzzy” lookups (à la C++’s std::map) where the nearest match can be returned, and so manipulations would be required to incoming sizes before being able to match them against a pre-existing lookup table. On the other hand, Array.BinarySearch will return the (binary, two’s complement) of the closest (higher) match if no exact match was found, letting us create a sorted list of formatting rules for each range, and then find the nearest match to service incoming requests.

In addition to converting numeric file sizes to formatted strings for human-readable representation, PrettySize also includes constants that can be used to make expressing your own size-related calculations easier, with both base 2 and base 10 units (and their abbreviations) exposed.

Some random facts learned in the process:

  • Exabyte is the only base 10 unit that isn’t 8 characters long, throwing a wrench in our code formatting for no good reason;
  • The corresponding base 2 unit, exbibyte, is a bit of an oddly-named unit; although perhaps understandably so since the remainder of the base 2 units all have e as the second letter, and eebibyte is a bit.. difficult to pronounce.

Anyway, that’s all for now. Go ahead and grab PrettySize from NuGet or off of GitHub and make life easier on yourself and your end users’ eyes!

Download: PrettySize 2.1.0

  1. If anyone wants to try their hand at implementing IFormattable, consider this an open invitation. It’s not a functionality we ever needed, but some might find it useful. 

Leave a Reply

Your email address will not be published. Required fields are marked *