Article Index

File size FormatProvider

Please stop me if this functionality already exists somewhere in the Framework. I did some searching and came up empty. If it exists, let me know and I'll delete this post and we can all have a little chuckle at my expense.

I need to be able to display file sizes to a user. The files can be anywhere from bytes to gigabytes (no terabytes, yet). If I always display them in bytes - the numbers are so big, its hard to read. If I display them in megabytes, you lose a lot of granularity, etc. I want to display the file sizes in units that make sense depending on the magnitude. I need to format the numbers in a lot of different places, so I wasn't happy with repeatedly doing the necessary division everywhere.

Instead I created a simple ICustomFormatter named FileSizeFormatProvider. I created just enough functionality to meet my needs. Potential improvements would be to allow you to specify the initial units (currently assumes bytes), and also specify the output units (always show in MB, regardless of the size). These settings could be set through properties on the provider, or through the format specification string.

Thanks to David Hayden and his post on custom formatting that inspired my solution. Hopefully by posting this code I can save someone else the embarrassment of having to waste time on something so silly.

This program:

class Program

{

    static void Main(string[] args)

    {

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 100));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 2000));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 30000000));

        Console.WriteLine(String.Format(new FileSizeFormatProvider(), "File size: {0:fs}", 400000000000));

    }

}

displays this output:

File size: 100.00 B
File size: 1.95kB
File size: 28.61MB
File size: 372.53GB

using this class:

public class FileSizeFormatProvider : IFormatProvider, ICustomFormatter

{

    public object GetFormat(Type formatType)

    {

        if (formatType == typeof(ICustomFormatter)) return this;

        return null;

    }

    private const string fileSizeFormat = "fs";

    private const Decimal OneKiloByte = 1024M;

    private const Decimal OneMegaByte = OneKiloByte * 1024M;

    private const Decimal OneGigaByte = OneMegaByte * 1024M;

 

    public string Format(string format, object arg, IFormatProvider formatProvider)

    {

        if (format == null || !format.StartsWith(fileSizeFormat))

        {

            return defaultFormat(format, arg, formatProvider);

        }

        if (arg is string)

        {

            return defaultFormat(format, arg, formatProvider);

        }

        Decimal size;

        try

        {

            size = Convert.ToDecimal(arg);

        }

        catch (InvalidCastException)

        {

            return defaultFormat(format, arg, formatProvider);

        }

 

        string suffix;

        if (size > OneGigaByte)

        {

            size /= OneGigaByte;

            suffix = "GB";

        }

        else if (size > OneMegaByte)

        {

            size /= OneMegaByte;

            suffix = "MB";

        }

        else if (size > OneKiloByte)

        {

            size /= OneKiloByte;

            suffix = "kB";

        }

        else

        {

            suffix = " B";

        }

        string precision = format.Substring(2);

        if (String.IsNullOrEmpty(precision)) precision = "2";

        return String.Format("{0:N" + precision + "}{1}", size, suffix);

    }

 

    private static string defaultFormat(string format, object arg, IFormatProvider formatProvider)

    {

        IFormattable formattableArg = arg as IFormattable;

        if (formattableArg != null)

        {

            return formattableArg.ToString(format, formatProvider);

        }

        return arg.ToString();

    }

}

Comments

Thank you!
Thats exactly what I needed : )
cr4zy - April 17, 2007 01:35am
Thanks for saving me the embarrassment of implementing something so silly! I'm using it in SeeMS in the pwiz project: proteowizard.sourceforge.net
Matt Chambers - July 14, 2008 10:45am