web-dev-qa-db-fra.com

Conversion d'octets en Go en C #?

Je refactais un ancien code et suis tombé sur la ligne de code suivante pour convertir des octets en Go.

decimal GB = KB / 1024 / 1024 / 1024;

Existe-t-il un meilleur moyen de refactoriser le code suivant?

Mettre à jour

Je voulais dire octets en gigaoctets. J'ai donné de fausses informations.

30
Michael Kniskern

J'ai développé cette méthode ici, fonctionne jusqu'à la tuberculose.

private static string FormatBytes(long bytes)
{
    string[] Suffix = { "B", "KB", "MB", "GB", "TB" };
    int i;
    double dblSByte = bytes;
    for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024) 
    {
        dblSByte = bytes / 1024.0;
    }

    return String.Format("{0:0.##} {1}", dblSByte, Suffix[i]);
}
87
JLopez

Si la précision exacte n'est pas importante, utilisez le double:

double gb = kb / 1048576D

D'accord avec Pavel ici - il n'y a pas vraiment besoin de refactoriser ce code ... en fait, s'il s'agit du plus gros problème de votre base de code, je pense que vous êtes peut-être assis sur le logiciel le plus bien écrit de tous les temps.

18
Rex M

Le code original est succinct, facile à lire et avec des noms de variables raisonnables, auto-documenté. Je ne changerais pas ça.

Si vous devez absolument refactoriser, vous pouvez créer un ensemble de méthodes d'extension sur les types numériques:

public static double BytesToKilobytes(this Int32 bytes)
{
    return bytes / 1024d;
}
public static double BytesToMegabytes(this Int32 bytes)
{
    return bytes / 1024d / 1024d;
}
public static double KilobytesToBytes(this double kilobytes)
{
    return kilobytes * 1024d;
}

//You can then do something like:
double filesize = 32.5d;
double bytes = filesize.KilobytesToBytes();

Mais à moins que votre code ne fasse pratiquement que convertir des octets en kilo-octets, etc., tout ce que cela fera vraiment, c'est d'encombrer Intellisense sans aucun gain réel.

7
technophile
    /// <summary>
/// Function to convert the given bytes to either Kilobyte, Megabyte, or Gigabyte
/// </summary>
/// <param name="bytes">Double -> Total bytes to be converted</param>
/// <param name="type">String -> Type of conversion to perform</param>
/// <returns>Int32 -> Converted bytes</returns>
/// <remarks></remarks>
public static double ConvertSize(double bytes, string type)
{
    try
    {
        const int CONVERSION_VALUE = 1024;
        //determine what conversion they want
        switch (type)
        {
            case "BY":
                 //convert to bytes (default)
                 return bytes;
            case "KB":
                 //convert to kilobytes
                 return (bytes / CONVERSION_VALUE);
            case "MB":
                 //convert to megabytes
                 return (bytes / CalculateSquare(CONVERSION_VALUE));
            case "GB":
                 //convert to gigabytes
                 return (bytes / CalculateCube(CONVERSION_VALUE));
            default:
                 //default
                 return bytes;
          }
     }
     catch (Exception ex)
     {
         Console.WriteLine(ex.Message);
         return 0;
      }
}

/// <summary>
/// Function to calculate the square of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be squared</param>
/// <returns>Double -> THe provided number squared</returns>
/// <remarks></remarks>
public static double CalculateSquare(Int32 number)
{
     return Math.Pow(number, 2);
}


/// <summary>
/// Function to calculate the cube of the provided number
/// </summary>
/// <param name="number">Int32 -> Number to be cubed</param>
/// <returns>Double -> THe provided number cubed</returns>
/// <remarks></remarks>
public static double CalculateCube(Int32 number)
{
     return Math.Pow(number, 3);
}

//Sample Useage
String Size = "File is " + ConvertSize(250222,"MB") + " Megabytes in size"
4
AZ_

J'ai écrit une petite classe utilitaire qui effectue des conversions entre unités, hth ..

#region StorageDifferential
/// <summary>
/// Converts between Base 2 or Base 10 storage units [TB, GB, MB, KB, Bytes]
/// </summary>
public enum Differential : int
{
    /// <summary>
    /// Convert Bytes to Kilobytes
    /// </summary>
    ByteToKilo,
    /// <summary>
    /// Convert Bytes to Megabytes
    /// </summary>
    ByteToMega,
    /// <summary>
    /// Convert Bytes to Gigabytes
    /// </summary>
    ByteToGiga,
    /// <summary>
    /// Convert Bytes to Teraytes
    /// </summary>
    ByteToTera,
    /// <summary>
    /// Convert Kilobytes to Bytes
    /// </summary>
    KiloToByte,
    /// <summary>
    /// Convert Kilobytes to Megabytes
    /// </summary>
    KiloToMega,
    /// <summary>
    /// Convert Kilobytes to Gigabytes
    /// </summary>
    KiloToGiga,
    /// <summary>
    /// Convert Kilobytes to Terabytes
    /// </summary>
    KiloToTera,
    /// <summary>
    /// Convert Megabytes to Bytes
    /// </summary>
    MegaToByte,
    /// <summary>
    /// Convert Megabytes to Kilobytes
    /// </summary>
    MegaToKilo,
    /// <summary>
    /// Convert Megabytes to Gigabytes
    /// </summary>
    MegaToGiga,
    /// <summary>
    /// Convert Megabytes to Terabytes
    /// </summary>
    MegaToTera,
    /// <summary>
    /// Convert Gigabytes to Bytes
    /// </summary>
    GigaToByte,
    /// <summary>
    /// Convert Gigabytes to Kilobytes
    /// </summary>
    GigaToKilo,
    /// <summary>
    /// Convert Gigabytes to Megabytes
    /// </summary>
    GigaToMega,
    /// <summary>
    /// Convert Gigabytes to Terabytes
    /// </summary>
    GigaToTerra,
    /// <summary>
    /// Convert Terabyte to Bytes
    /// </summary>
    TeraToByte,
    /// <summary>
    /// Convert Terabyte to Kilobytes
    /// </summary>
    TeraToKilo,
    /// <summary>
    /// Convert Terabytes to Megabytes
    /// </summary>
    TeraToMega,
    /// <summary>
    /// Convert Terabytes to Gigabytes
    /// </summary>
    TeraToGiga,
}
#endregion

#region Storage Sizes
/// <summary>
/// Enumeration of recognized storage sizes [in Bytes]
/// </summary>
public enum StorageSizes : long
{
    /// <summary>
    /// Base 10 Conversion
    /// </summary>
    KILOBYTE = 1000,
    MEGABYTE = 1000000,
    GIGABYTE = 1000000000,
    TERABYTE = 1000000000000,
    /// <summary>
    /// Base 2 Conversion
    /// </summary>
    KIBIBYTE = 1024,
    MEBIBYTE = 1048576,
    GIBIBYTE = 1073741824,
    TEBIBYTE = 1099511627776,
}
#endregion

#region StorageBase
/// <summary>
/// Storage powers 10 based or 1024 based
/// </summary>
public enum StorageBase : int
{
    /// <summary>
    /// 1024 Base power, Typically used in memory measurements
    /// </summary>
    BASE2,
    /// <summary>
    /// 10 Base power, Used in storage mediums like harddrives
    /// </summary>
    BASE10,
}
#endregion

/// <summary>
/// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
/// </summary>
public static class StorageConverter
{
    /// <summary>
    /// Convert between base 1024 storage units [TB, GB, MB, KB, Byte]
    /// </summary>
    /// <param name="SizeDifferential">Storage conversion differential [enum]</param>
    /// <param name="UnitSize">Size as mutiple of unit type units [double]</param>
    /// <param name="BaseUnit">Size of the base power [enum]</param>
    /// <returns>Converted unit size [double]</returns>
    public static double Convert(Differential SizeDifferential, double UnitSize, StorageBase BaseUnit = StorageBase.BASE10)
    {
        if (UnitSize < 0.000000000001) return 0;

        double POWER1 = 1000;
        double POWER2 = 1000000;
        double POWER3 = 1000000000;
        double POWER4 = 1000000000000;

        if (BaseUnit == StorageBase.BASE2)
        {
            POWER1 = 1024;
            POWER2 = 1048576;
            POWER3 = 1073741824;
            POWER4 = 1099511627776;
        }

        switch (SizeDifferential)
        {
            case Differential.ByteToKilo:
                return UnitSize / POWER1;
            case Differential.ByteToMega:
                return UnitSize / POWER2;
            case Differential.ByteToGiga:
                return UnitSize / POWER3;
            case Differential.ByteToTera:
                return UnitSize / POWER4;
            case Differential.KiloToByte:
                return UnitSize * POWER1;
            case Differential.KiloToMega:
                return UnitSize / POWER1;
            case Differential.KiloToGiga:
                return UnitSize / POWER2;
            case Differential.KiloToTera:
                return UnitSize / POWER3;
            case Differential.MegaToByte:
                return UnitSize * POWER2;
            case Differential.MegaToKilo:
                return UnitSize * POWER1;
            case Differential.MegaToGiga:
                return UnitSize / POWER1;
            case Differential.MegaToTera:
                return UnitSize / POWER2;
            case Differential.GigaToByte:
                return UnitSize * POWER3;
            case Differential.GigaToKilo:
                return UnitSize * POWER2;
            case Differential.GigaToMega:
                return UnitSize * POWER1;
            case Differential.GigaToTerra:
                return UnitSize / POWER1;
            case Differential.TeraToByte:
                return UnitSize * POWER4;
            case Differential.TeraToKilo:
                return UnitSize * POWER3;
            case Differential.TeraToMega:
                return UnitSize * POWER2;
            case Differential.TeraToGiga:
                return UnitSize * POWER1;
        }

        return 0;
    }
}
2
JGU

Eh bien, la formule est fausse (il n'y a qu'environ un million de kilo-octets dans un gigaoctet, pas un millier de millions) mais, mis à part cela, tout va bien. Quiconque a l'habitude de travailler avec ces chiffres saura ce que cela signifie.

Une chose à laquelle je ferais attention (et je ne sais pas s'il s'agit d'un problème avec C #) est qu'un compilateur peut ne pas être capable d'optimiser le x/1024/1024 si x n'est pas un type basique. Avec C et les nombres entiers, le compilateur le transformerait assez facilement en une instruction "aveuglante-rapide-décalée-droite-de-20 bits".

Si décimal est une classe plutôt qu'un type de base, le compilateur peut être amené à effectuer deux opérations de division. Que cela ait un impact réel sur la vitesse (ou même que cela se produise) est en dehors de ma sphère de connaissances.

Une chose que je considérerais changer est le nom des variables réelles. Cela ne change pas vraiment le code compilé, mais je préfère les noms de variables plus longs aux abréviations. Je choisirais donc kiloBytes/gigaBytes ou quelque chose du genre. KB/GB est trop facile à confondre avec les constantes, en fonction de vos normes de codage.

2
paxdiablo

En théorie, c'est plus rapide (précalculer la constante pour faire la multiplication au lieu de la division). Ce n'est probablement pas assez utilisé pour importer, mais juste au cas où.

double const KbToGbFactor = 1d / 1024 /1024;

double gb = kb * KbToGbFactor;
2
Kenan E. K.

Personnellement, j'écrirais ceci comme ceci: decimal GB = KB / (1024 * 1024); mais il n'y a vraiment pas besoin de refactoriser le code tel qu'il est écrit.

2
mattnewport

Pour vous assurer que le compilateur pré-calcule les diviseurs:

decimal GB = KB / (1024 * 1024);

Notez que vous calculez réellement GiB (gibioctets), et non Go (gigaoctets). Si vous voulez vraiment calculer le Go, ce serait:

decimal GB = KB / (1000 * 1000);
1
Guffa

Ceci est une petite amélioration de la bonne réponse de JLopez (SVP VOTEZ-LE, pas moi). Ici, vous pouvez choisir d’indiquer ou non l’indication des unités et l’unité kilo est écrite avec la minuscule "k" (la majuscule). on est pour Kelvin)

//note: this is the JLopez answer!!
/// <summary>
/// Return size in human readable form
/// </summary>
/// <param name="bytes">Size in bytes</param>
/// <param name="useUnit ">Includes measure unit (default: false)</param>
/// <returns>Readable value</returns>
public static string FormatBytes(long bytes, bool useUnit = false)
    {
        string[] Suffix = { " B", " kB", " MB", " GB", " TB" };
        double dblSByte = bytes;
        int i;
        for (i = 0; i < Suffix.Length && bytes >= 1024; i++, bytes /= 1024)
        {
            dblSByte = bytes / 1024.0;
        }
        return $"{dblSByte:0.##}{(useUnit ? Suffix[i] : null)}";
    }
1
tedebus

J'en avais besoin dans l'autre sens, convertir la taille littérale du composant tiers en mots (par exemple, "0 octet", "1,1 Mo") en taille générique en octets. donc je l'ai utilisé de cette façon:

        private static long UnformatBytes(string sizeInWords)
    {
        if(string.IsNullOrWhiteSpace(sizeInWords))
            return -1;

        string size = sizeInWords.Split(' ').FirstOrDefault();
        double result;
        if (string.IsNullOrWhiteSpace(size) || !double.TryParse(size, out result))
        {
            Debugger.Break();
            return -1;
        }

        int pow;

        if (sizeInWords.IndexOf("byte", StringComparison.OrdinalIgnoreCase) > -1)
            pow = 0;
        else if (sizeInWords.IndexOf("kb", StringComparison.OrdinalIgnoreCase) > -1)
            pow = 1;
        else if (sizeInWords.IndexOf("mb", StringComparison.OrdinalIgnoreCase) > -1)
            pow = 2;
        else if (sizeInWords.IndexOf("gb", StringComparison.OrdinalIgnoreCase) > -1)
            pow = 3;
        else if (sizeInWords.IndexOf("tb", StringComparison.OrdinalIgnoreCase) > -1)
            pow = 4;
        else
            return -1;

        return System.Convert.ToInt64((result * Math.Pow(1024, pow)));
    }
1
Elad Tal
#region AutoFileSize
    public string AutoFileSize(long number)
    {
        double tmp = number;
        string suffix = " B ";
        if (tmp > 1024) { tmp = tmp / 1024; suffix = " KB"; }
        if (tmp > 1024) { tmp = tmp / 1024; suffix = " MB"; }
        if (tmp > 1024) { tmp = tmp / 1024; suffix = " GB"; }
        if (tmp > 1024) { tmp = tmp / 1024; suffix = " TB"; }
        return tmp.ToString("n") + suffix;
    }
    #endregion

long number = (long)fu.PostedFile.ContentLength;
0
user3958481
    public static string BytesToString(this long bytes, string format = "#,##0.00") {
        var unitstr = new string[] { "B", "KB", "MB", "GB", "TB" };
        var bytesd = Convert.ToDouble(bytes);
        var unit = 0;
        while (bytesd / 1024D > 1 && unit < unitstr.Length) {
            unit++; bytesd /= 1024D;
        }
        return string.Format("{0:" + format + "}{1}", bytesd, unitstr[unit]);
    }
0
Leo