using System;
namespace Vanara
{
///
/// A custom formatter for byte sizes (things like files, network bandwidth, etc.) that will automatically determine the best abbreviation.
///
public class ByteSizeFormatter : Formatter
{
private static readonly string[] suffixes = { " B", " KB", " MB", " GB", " TB", " PB", " EB" };
/// A static instance of .
public static readonly ByteSizeFormatter Instance = new ByteSizeFormatter();
///
/// Converts the value of a specified object to an equivalent string representation using specified format and culture-specific
/// formatting information.
///
/// A format string containing formatting specifications.
/// An object to format.
/// An object that supplies format information about the current instance.
///
/// The string representation of the value of , formatted as specified by and
/// .
///
public override string Format(string format, object arg, IFormatProvider formatProvider)
{
long bytes;
try { bytes = Convert.ToInt64(arg); }
catch { return HandleOtherFormats(format, arg); }
if (bytes == 0) return "0" + suffixes[0];
var m = System.Text.RegularExpressions.Regex.Match(format, @"^[B|b](?\d+)?$");
if (!m.Success) return HandleOtherFormats(format, arg);
var prec = m.Groups["prec"].Success ? byte.Parse(m.Groups["prec"].Value) : 0;
var place = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024)));
if (place >= suffixes.Length) place = suffixes.Length - 1;
var num = Math.Round(bytes / Math.Pow(1024, place), 1);
return $"{num.ToString("F" + prec).TrimEnd('0')}{suffixes[place]}";
}
///
/// Converts the string representation of a byte size to its 64-bit signed integer equivalent. A return value indicates whether the
/// conversion succeeded.
///
/// A string containing a byte size to convert.
///
/// When this method returns, contains the 64-bit signed integer value equivalent of the value contained in ,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the parameter is
/// null or Empty, or is not of the correct format. This parameter is passed uninitialized; any value originally supplied in result
/// will be overwritten.
///
/// if was converted successfully; otherwise, .
///
public static bool TryParse(string input, out long bytes)
{
const string expr = @"^\s*(?\d+(?:\.\d+)?)\s*(?[kKmMgGtTpPeEyY]?[bB])?\s*$";
var match = System.Text.RegularExpressions.Regex.Match(input, expr);
bytes = 0;
if (!match.Success) return false;
long mult = 1;
switch (match.Groups["mod"].Value.ToUpper())
{
case "B":
case "":
break;
case "KB":
mult = 1024;
break;
case "MB":
mult = (long)Math.Pow(1024, 2);
break;
case "GB":
mult = (long)Math.Pow(1024, 3);
break;
case "TB":
mult = (long)Math.Pow(1024, 4);
break;
case "PB":
mult = (long)Math.Pow(1024, 5);
break;
case "EB":
mult = (long)Math.Pow(1024, 6);
break;
case "YB":
mult = (long)Math.Pow(1024, 7);
break;
default:
throw new InvalidOperationException();
}
bytes = (long)Math.Round(float.Parse(match.Groups["num"].Value) * mult);
return true;
}
}
}