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 } }