using System;
using System.Globalization;
using Developpez.Dotnet.Properties;
namespace Developpez.Dotnet
{
///
/// Permet de formater une taille en octets de façon lisible pour l'utilisateur
///
public class ByteSizeFormatter
{
#region Prefixes and multiples definitions
private static readonly long[] _decimalMultiples = new[]
{
1L,
1000L,
1000000L,
1000000000L,
1000000000000L,
1000000000000000L,
1000000000000000000L
};
private static readonly long[] _binaryMultiples = new[]
{
1L,
1024L,
1024L * 1024L,
1024L * 1024L * 1024L,
1024L * 1024L * 1024L * 1024L,
1024L * 1024L * 1024L * 1024L * 1024L,
1024L * 1024L * 1024L * 1024L * 1024L * 1024L,
};
private static readonly string[] _binaryPrefixes = new[]
{
"",
"Ki",
"Mi",
"Gi",
"Ti",
"Pi",
"Ei",
};
private static readonly string[] _decimalPrefixes = new[]
{
"",
"K",
"M",
"G",
"T",
"P",
"E",
};
#endregion
#region Private data
private int _decimalPlaces;
private string _numberFormat;
private ByteSizeUnit _minUnit;
private ByteSizeUnit _maxUnit;
private ByteSizeRounding _roundingRule;
#endregion
#region Constructor
///
/// Crée une nouvelle instance de ByteSizeFormatter
///
public ByteSizeFormatter()
{
DecimalPlaces = 0;
NumberFormat = "#,##0.###";
Convention = ByteSizeConvention.Customary;
MinUnit = ByteSizeUnit.Byte;
MaxUnit = ByteSizeUnit.Exabyte;
RoundingRule = ByteSizeRounding.Closest;
UseFullWordForBytes = true;
}
#endregion
#region Public properties
///
/// Obtient ou définit la convention utilisée pour les unités de taille.
///
/// La convention utilisée pour les unités de taille. La valeur par défaut est ByteSizeConvention.Customary, qui correspond à l'usage courant.
public ByteSizeConvention Convention { get; set; }
///
/// Obtient ou définit la culture à utiliser pour le formatage du nombre.
///
/// La culture à utiliser, ou null pour utiliser la culture courante. La valeur par défaut est null.
public CultureInfo Culture { get; set; }
///
/// Obtient ou définit le nombre de chiffres après la virgule à afficher.
///
/// Le nombre de chiffres après la virgule à afficher. La valeur par défaut est 0.
public int DecimalPlaces
{
get { return _decimalPlaces; }
set
{
value.CheckArgumentOutOfRange("value", 0, int.MaxValue);
_decimalPlaces = value;
}
}
///
/// Obtient ou définit le format d'affichage de la valeur.
///
/// Le format d'affichage de la valeur. La valeur par défaut est "#,##0.###".
public string NumberFormat
{
get { return _numberFormat; }
set
{
value.CheckArgumentNull("value");
_numberFormat = value;
}
}
///
/// Obtient ou définit l'unité la plus petite à utiliser.
///
/// L'unité la plus petite à utiliser. La valeur par défaut est ByteSizeUnit.Byte.
public ByteSizeUnit MinUnit
{
get { return _minUnit; }
set
{
value.CheckArgumentInEnum("value");
_minUnit = value;
if (_maxUnit < _minUnit)
_maxUnit = _minUnit;
}
}
///
/// Obtient ou définit l'unité la plus grande à utiliser.
///
/// L'unité la plus grande à utiliser. La valeur par défaut est ByteSizeUnit.ExaByte.
public ByteSizeUnit MaxUnit
{
get { return _maxUnit; }
set
{
value.CheckArgumentInEnum("value");
_maxUnit = value;
if (_minUnit > _maxUnit)
_minUnit = _maxUnit;
}
}
///
/// Obtient ou définit la règle d'arrondi à utiliser.
///
/// La règle d'arrondi à utiliser. La valeur par défaut est ByteSizeRounding.Closest (arrondi au plus proche).
public ByteSizeRounding RoundingRule
{
get { return _roundingRule; }
set
{
value.CheckArgumentInEnum("value");
_roundingRule = value;
}
}
///
/// Obtient ou définit une valeur indiquant si les tailles inférieures à 1 Ko
/// sont affichées avec le mot "octet" non abrégé.
///
/// true pour afficher le mot "octet" non abrégé pour les tailles inférieures à 1 Ko,
/// false pour afficher l'abréviation. La valeur par défaut est true.
public bool UseFullWordForBytes { get; set; }
#endregion
///
/// Formate la taille spécifiée.
///
/// La taille à formater
/// La taille formatée avec les options de ce ByteSizeFormatter
public string Format(long size)
{
if (size < 0)
throw new ArgumentOutOfRangeException(
"size",
string.Format(ExceptionMessages.NumberMustBePositiveOrZero, "size"));
long[] multiples = _binaryMultiples;
string[] prefixes = _decimalPrefixes;
switch (Convention)
{
case ByteSizeConvention.Binary:
//case ByteSizeConvention.IEC:
multiples = _binaryMultiples;
prefixes = _binaryPrefixes;
break;
case ByteSizeConvention.Decimal:
//case ByteSizeConvention.SI:
multiples = _decimalMultiples;
prefixes = _decimalPrefixes;
break;
case ByteSizeConvention.Customary:
multiples = _binaryMultiples;
prefixes = _decimalPrefixes;
break;
}
int k = (int)MinUnit;
for (int i = k; i <= (int)MaxUnit; i++)
{
if (size < multiples[i])
break;
k = i;
}
string byteText = Resources.ResourceManager.GetString("ByteSymbol", Culture);
if (UseFullWordForBytes && k == 0)
{
byteText = size > 1
? Resources.ResourceManager.GetString("Bytes", Culture)
: Resources.ResourceManager.GetString("Byte", Culture);
}
decimal valueToDisplay = Round((decimal) size / multiples[k]);
return string.Format(
"{0} {1}{2}",
valueToDisplay.ToString(NumberFormat, Culture),
prefixes[k],
byteText);
}
private decimal Round(decimal value)
{
if (RoundingRule == ByteSizeRounding.Closest)
return Math.Round(value, DecimalPlaces);
decimal factor = (decimal)Math.Pow(10, DecimalPlaces);
Func roundFunc = decimal.Ceiling;
if (RoundingRule == ByteSizeRounding.Down)
roundFunc = decimal.Floor;
return roundFunc(value * factor) / factor;
}
}
///
/// Définit la convention utilisée pour les unités de taille en octets.
///
public enum ByteSizeConvention
{
///
/// Convention d'usage courant : multiples binaires (1024), préfixes décimaux (K/M/G...).
///
Customary,
///
/// Convention binaire : multiples binaires (1024), préfixes binaires (Ki/Mi/Gi...).
/// Equivalent à IEC.
///
Binary,
///
/// Convention décimale : multiples décimaux (1000), préfixes décimaux (K/M/G...).
/// Equivalent à SI.
///
Decimal,
///
/// Convention IEC 60027 : multiples binaires (1024), préfixes binaires (Ki/Mi/Gi...).
/// Equivalent à Binary.
///
IEC = Binary,
///
/// Convention du système international : multiples décimaux (1000), préfixes décimaux (K/M/G...).
/// Equivalent à Decimal.
///
SI = Decimal
}
///
/// Définit les unités de taille en octets.
///
public enum ByteSizeUnit
{
///
/// Octet
///
Byte,
///
/// kilooctet, ou kibioctet en convention binaire
///
Kilobyte,
///
/// mégaoctet, ou mébioctet en convention binaire
///
Megabyte,
///
/// gigaoctet, ou gibioctet en convention binaire
///
Gigabyte,
///
/// téraoctet, ou tébioctet en convention binaire
///
Terabyte,
///
/// pétaoctet, ou pébioctet en convention binaire
///
Petabyte,
///
/// exaoctet, ou exbioctet en convention binaire
///
Exabyte
}
///
/// Définit les règles d'arrondi pour les tailles en octets.
///
public enum ByteSizeRounding
{
///
/// Arrondi à la valeur la plus proche
///
Closest,
///
/// Arrondi à la valeur inférieure
///
Down,
///
/// Arrondi à la valeur supérieure
///
Up
}
}