Does .NET provide an easy way convert bytes to KB, MB, GB, etc.?
Solution 1
Here is a fairly concise way to do this:
static readonly string[] SizeSuffixes =
{ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
if (decimalPlaces < 0) { throw new ArgumentOutOfRangeException("decimalPlaces"); }
if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); }
if (value == 0) { return string.Format("{0:n" + decimalPlaces + "} bytes", 0); }
// mag is 0 for bytes, 1 for KB, 2, for MB, etc.
int mag = (int)Math.Log(value, 1024);
// 1L << (mag * 10) == 2 ^ (10 * mag)
// [i.e. the number of bytes in the unit corresponding to mag]
decimal adjustedSize = (decimal)value / (1L << (mag * 10));
// make adjustment when the value is large enough that
// it would round up to 1000 or more
if (Math.Round(adjustedSize, decimalPlaces) >= 1000)
{
mag += 1;
adjustedSize /= 1024;
}
return string.Format("{0:n" + decimalPlaces + "} {1}",
adjustedSize,
SizeSuffixes[mag]);
}
And here's the original implementation I suggested, which may be marginally slower, but a bit easier to follow:
static readonly string[] SizeSuffixes =
{ "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(Int64 value, int decimalPlaces = 1)
{
if (value < 0) { return "-" + SizeSuffix(-value, decimalPlaces); }
int i = 0;
decimal dValue = (decimal)value;
while (Math.Round(dValue, decimalPlaces) >= 1000)
{
dValue /= 1024;
i++;
}
return string.Format("{0:n" + decimalPlaces + "} {1}", dValue, SizeSuffixes[i]);
}
Console.WriteLine(SizeSuffix(100005000L));
One thing to bear in mind - in SI notation, "kilo" usually uses a lowercase k while all of the larger units use a capital letter. Windows uses KB, MB, GB, so I have used KB above, but you may consider kB instead.
Solution 2
Checkout the ByteSize library. It's the System.TimeSpan
for bytes!
It handles the conversion and formatting for you.
var maxFileSize = ByteSize.FromKiloBytes(10);
maxFileSize.Bytes;
maxFileSize.MegaBytes;
maxFileSize.GigaBytes;
It also does string representation and parsing.
// ToString
ByteSize.FromKiloBytes(1024).ToString(); // 1 MB
ByteSize.FromGigabytes(.5).ToString(); // 512 MB
ByteSize.FromGigabytes(1024).ToString(); // 1 TB
// Parsing
ByteSize.Parse("5b");
ByteSize.Parse("1.55B");
Solution 3
I would solve it using Extension methods
, Math.Pow
function and Enums
:
public static class MyExtension
{
public enum SizeUnits
{
Byte, KB, MB, GB, TB, PB, EB, ZB, YB
}
public static string ToSize(this Int64 value, SizeUnits unit)
{
return (value / (double)Math.Pow(1024, (Int64)unit)).ToString("0.00");
}
}
and use it like:
string h = x.ToSize(MyExtension.SizeUnits.KB);
Solution 4
Since everyone else is posting their methods, I figured I'd post the extension method I usually use for this:
EDIT: added int/long variants...and fixed a copypasta typo...
public static class Ext
{
private const long OneKb = 1024;
private const long OneMb = OneKb * 1024;
private const long OneGb = OneMb * 1024;
private const long OneTb = OneGb * 1024;
public static string ToPrettySize(this int value, int decimalPlaces = 0)
{
return ((long)value).ToPrettySize(decimalPlaces);
}
public static string ToPrettySize(this long value, int decimalPlaces = 0)
{
var asTb = Math.Round((double)value / OneTb, decimalPlaces);
var asGb = Math.Round((double)value / OneGb, decimalPlaces);
var asMb = Math.Round((double)value / OneMb, decimalPlaces);
var asKb = Math.Round((double)value / OneKb, decimalPlaces);
string chosenValue = asTb > 1 ? string.Format("{0}Tb",asTb)
: asGb > 1 ? string.Format("{0}Gb",asGb)
: asMb > 1 ? string.Format("{0}Mb",asMb)
: asKb > 1 ? string.Format("{0}Kb",asKb)
: string.Format("{0}B", Math.Round((double)value, decimalPlaces));
return chosenValue;
}
}
Solution 5
I know this is old thread already. but maybe someone will look for solution. And here's what I use and the easiest way
public static string FormatFileSize(long bytes)
{
var unit = 1024;
if (bytes < unit) { return $"{bytes} B"; }
var exp = (int)(Math.Log(bytes) / Math.Log(unit));
return $"{bytes / Math.Pow(unit, exp):F2} {("KMGTPE")[exp - 1]}B";
}
Get folder size (for example usage)
public static long GetFolderSize(string path, string ext, bool AllDir)
{
var option = AllDir ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
return new DirectoryInfo(path).EnumerateFiles("*" + ext, option).Sum(file => file.Length);
}
EXAMPLE USAGE:
public static void TEST()
{
string folder = @"C:\Users\User\Videos";
var bytes = GetFolderSize(folder, "mp4", true); //or GetFolderSize(folder, "mp4", false) to get all single folder only
var totalFileSize = FormatFileSize(bytes);
Console.WriteLine(totalFileSize);
}
John Smith
Updated on March 29, 2022Comments
-
John Smith over 2 years
Just wondering if .NET provides a clean way to do this:
int64 x = 1000000; string y = null; if (x / 1024 == 0) { y = x + " bytes"; } else if (x / (1024 * 1024) == 0) { y = string.Format("{0:n1} KB", x / 1024f); }
etc...
-
fiat almost 3 yearsYou may consider the
UnitsNet
nuget package github.com/angularsen/UnitsNet/blob/master/UnitsNet/…
-
-
JLRishe over 11 yearsThe asker is only looking for 1 decimal place of accuracy. Could you give an example of an input that produces an incorrect output?
-
JLRishe over 10 yearsThe stated issue with large values should no longer be present in the accepted answer.
-
JLRishe over 10 yearsBoth examples now use floating point division so there should be much less concern about rounding errors.
-
snapplex about 10 yearsThank you, just what I was looking for. (2nd implementation.)
-
bounav almost 10 yearsVery neat implementation. Note that if you pass the value 0 to this function it will throw an IndexOutOfRangeException. I decided to add a
if (value == 0) { return "0"; }
check inside the function. -
The Joker over 9 yearsSimple to use and understand, and it works with .Net 4.0 and up.
-
Peter Majeed almost 8 years+1 - according to Wikipedia, kb => 1000 bytes, and KiB => 1024 bytes.
-
helios456 about 7 yearsThis should be included as part of the .NET framework
-
John Jang about 7 yearsMay I ask why you use
float.Parse
todouble
? -
yossico over 6 yearsElegant solution!
-
Louis Somers over 6 yearsI used your idea to create one that automatically determines the unit. +1
-
stoj over 6 yearsThat's a very elegant solution, which is much cleaner and consise that the approved solution. However, strictly speaking based on the enum values it should be based on power of 1000, i.e. not 1024 (en.wikipedia.org/wiki/Terabyte) code... public static string ToSize(this long value, Unit unit) => $"{value / Math.Pow(1000, (long) unit):F2}{unit.ToString()}";
-
SuperJMN almost 6 yearsThe only problem I see is that the conversion methods only work from non-byte to byte, but no the other way round.
-
Omar almost 6 years@SuperJMN what do you mean non-byte? Like bits? There’s a .FromBits method you can use.
-
SuperJMN almost 6 yearsSorry, I have not provided much info. I'm now testing your library. It's really cool! However I don't see how to convert a value (in bytes) to a ByteSize. Which method should I use? Thanks!
-
SuperJMN almost 6 yearsOK, I have just located it. It's the constructor of ByteSize! Wonderful :)
-
James Blake over 5 yearsIf your source data is something other than "bytes" and you need to be able to convert to anything...this is is the library you should be using.
-
Ruslan F. about 5 yearsCan you provide the case when file size is < 0 ? For me it looks weird...
-
JLRishe about 5 years@RuslanF. The difference in size between two files, or any size differential can be a negative number, so there's one use case. It's just one extra line to handle the < 0 case gracefully and I think that's better than having the method blow up with an IndexOutOfRangeException (in the first example) or do nothing useful at all (in the second example).
-
SharpC about 4 yearsUnlike the other values the k in kB is usually lowercase. :-) en.wikipedia.org/wiki/Kilobyte.
-
SharpC about 4 yearsBear in mind though that lowercase b can typically signify bits rather than bytes. :-) en.wikipedia.org/wiki/Data-rate_units#Kilobit_per_second
-
JLRishe about 4 years@SharpC Thanks, good point. Windows uses KB, so I'm going to leave it that way, but I have added a note.
-
Sergey Kovalev almost 4 yearsThis is the most elegant solution here.
-
zackmark15 almost 4 years@SergeyKovalev thanks :) I've been using this all the the time. Less cpu usage and easiy to use
-
Mike Christensen over 3 yearsRather than
> 1
I'd probably do>= 1
-
Tyler Forsythe almost 3 yearsIt seems that
OneKB, OneMB, OneGB, and OneTB
are all undefined here. Please update this code with those values or explain where they come from. Thanks! -
StFS almost 3 yearsKudos on mentioning this! I created a library for Java to do byte size conversions and hit the IEC vs SI wall there. In the end I went all in and support both. Now that I'm working in the .NET world I might port that over to C#. But until then and for educational purposes, here's a link to my Java lib: github.com/StFS/YummyBytes
-
Avrohom Yisroel about 2 yearsI wish I could vote for this more than once, it's sooooooo neat and elegant. Thank you very much
-
Frank Alvaro about 2 years@RuslanF - going along with @JLRishe's reply:
Microsoft.Extensions.FileProviders.IFileInfo.Length
can return "-1 for a directory or non-existing files", too.