Click here to Skip to main content
15,881,882 members
Articles / Programming Languages / C#
Tip/Trick

A simple "human scale" number to string converter

Rate me:
Please Sign up or sign in to vote.
4.88/5 (5 votes)
25 May 2014CPOL 16.7K   9   4
I needed to show file sizes in a "human friendly format" recently, so I thought I'd knock up a simple method to do it. So the file sizes such as 10123456789 bytes would display as 10.1Gb and so forth.

Introduction

I needed to show file sizes in a "human friendly format" recently, so I thought I'd knock up a simple method to do it. So the file sizes such as 10123456789 bytes would display as 10.1Gb and so forth. Simple, but a pain, since it breaks your concentration to "knock up" a method. I'm sure there are other versions out there, but...some of them are far too complicated for their own good!

The code

Easy to read, I think: it uses an array of ISO suffixes (in ISO they are prefixes, because they come before the quantity type: "G" is the prefix, "b" is the bytes in "12.3 Gb")

C#
/// <summary>
/// Suffix size values (ISO only goes up to "Yotta", but a 64bit int
/// can't even get there - the last two are for completeness.)
/// </summary>
///
private static string[] suffixes = new string[] { "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
/// <summary>
/// Converts a long value to a human scale count
///        Number  Human Scale
///             1  1
///            10  10
///           101  101
///          1012  1.01k
///         10123  10.1k
///        101234  101k
///       1012345  1.01M
///      10123456  10.1M
///     101234567  101M
///    1012345678  1.01G
///             ....
/// </summary>
/// <param name="value">Value to scale</param>
/// <param name="suffix">If supplied, appended to the output string</param>
/// <param name="spacer">If supplied, it separates the numbers and the ISO size indicator</param>
/// <param name="positiveIndicator">If supplied, it prefixes the number</param>
/// <returns></returns>
public static string HumanScale(long value, string suffix = "", string spacer = "", string positiveIndicator = "")
    {
    string result = Math.Abs(value).ToString();
    int digits = result.Length;
    if (digits >= 4)
        {
        digits--;       // Groups = (Length - 1) / sizeOfGroup;
                        // digitsBeforeDecimal = ((Length - 1) % 3) + 1
                        // This avoids testing and "move down" of groups count
                        // when we don't want a decimal at all: 123M for example.
        int groups = digits / 3;
        int digitsBeforeDecimal = digits % 3;
        StringBuilder sb = new StringBuilder();
        foreach (char c in result.Substring(0, 3))
            {
            if (digitsBeforeDecimal == -1) sb.Append(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator);
            digitsBeforeDecimal--;
            sb.Append(c);
            }
        result = string.Format("{0}{1}{2}{3}", sb, spacer, suffixes[groups], suffix);
        }
    return string.Format("{0}{1}", value < 0 ? System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NegativeSign : positiveIndicator, result);
    }

Using it is also simple:

C#
long l = 1;
for (int i = 0; i <= 24; i++)
    {
    Console.WriteLine("{0,2} {1,24}  {2}", i, l, HumanScale(l));
    l = (l * 10) + (i % 10);
    }

Generates:

 0                        1  1
 1                       10  10
 2                      101  101
 3                     1012  1.01k
 4                    10123  10.1k
 5                   101234  101k
 6                  1012345  1.01M
 7                 10123456  10.1M
 8                101234567  101M
 9               1012345678  1.01G
10              10123456789  10.1G
11             101234567890  101G
12            1012345678901  1.01T
13           10123456789012  10.1T
14          101234567890123  101T
15         1012345678901234  1.01P
16        10123456789012345  10.1P
17       101234567890123456  101P
18      1012345678901234567  1.01E
19     -8323287284697205938  -8.32E
20      9000847521575698709  9.00E
21     -2225245152790770990  -2.22E
22     -3805707454198158283  -3.80E
23     -1163586394562479596  -1.16E
24      6810880128084755659  6.81E

Note that the long value overflows long before Yottabytes are reached!

History

2014-05-25 Original version

2014-05-25 XML comments un-mucked up. Editor removed closing tags, and so forth - so they would have been invalid in Visual Studio when copy / pasted. I do dislike this editor, sometimes...

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO
Wales Wales
Born at an early age, he grew older. At the same time, his hair grew longer, and was tied up behind his head.
Has problems spelling the word "the".
Invented the portable cat-flap.
Currently, has not died yet. Or has he?

Comments and Discussions

 
QuestionShortening made easier Pin
veeRob9-Jun-14 12:46
veeRob9-Jun-14 12:46 
SuggestionWhat about using the OS functions? Pin
DaveAuld25-May-14 19:11
professionalDaveAuld25-May-14 19:11 
Print File Size[^]

That would then provide standard appearance with the OS.
GeneralRe: What about using the OS functions? Pin
Ravi Bhavnani26-May-14 2:37
professionalRavi Bhavnani26-May-14 2:37 
QuestionVery useful... Pin
Louis van Alphen25-May-14 6:44
Louis van Alphen25-May-14 6:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.