Je me demande simplement si .NET fournit un moyen propre de le faire:

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

c#
96
omega 4 nov. 2019 à 03:36

18 réponses

@ Réponse de Servy était agréable et succinct. Je pense que cela peut être encore plus simple?

private static string[] suffixes = new [] { " B", " KB", " MB", " GB", " TB", " PB" };

public static string ToSize(double number, int precision = 2)
{
    // unit's number of bytes
    const double unit = 1024;
    // suffix counter
    int i = 0;
    // as long as we're bigger than a unit, keep going
    while(number > unit)
    {
        number /= unit;
        i++;
    }
    // apply precision and current suffix
    return Math.Round(number, precision) + suffixes[i];
}
2
drzaus 26 janv. 2018 à 18:44

J'utilise ceci pour Windows (préfixes binaires):

static readonly string[] BinaryPrefix = { "bytes", "KB", "MB", "GB", "TB" }; // , "PB", "EB", "ZB", "YB"
string GetMemoryString(double bytes)
{
    int counter = 0;
    double value = bytes;
    string text = "";
    do
    {
        text = value.ToString("0.0") + " " + BinaryPrefix[counter];
        value /= 1024;
        counter++;
    }
    while (Math.Floor(value) > 0 && counter < BinaryPrefix.Length);
    return text;
}
0
A.J.Bauer 12 juin 2018 à 08:52

Comme indiqué ci-dessus, la récursivité est le moyen préféré, à l'aide du logarithme.

La fonction suivante a 3 arguments: l'entrée, la contrainte de dimension de la sortie, c'est le troisième argument.

int ByteReDim(unsigned long ival, int constraint, unsigned long *oval)
{
    int base = 1 + (int) log10(ival);

    (*oval) = ival;
    if (base > constraint) {
        (*oval) = (*oval) >> 10;
        return(1 + ByteReDim((*oval), constraint, oval));
    } else
        return(0);
}

Convertissons maintenant 12 Go de RAM en plusieurs unités:

int main(void)
{
    unsigned long RAM;
    int unit; // index of below symbols array
    char symbol[5] = {'B', 'K', 'M', 'G', 'T'};

    unit = ByteReDim(12884901888, 12, &RAM);
    printf("%lu%c\n", RAM, symbol[unit]); // output is 12884901888B

    unit = ByteReDim(12884901888, 9, &RAM);
    printf("%lu%c\n", RAM, symbol[unit]); // output is 12582912K

    unit = ByteReDim(12884901888, 6, &RAM);
    printf("%lu%c\n", RAM, symbol[unit]); // output is 12288M

    unit = ByteReDim(12884901888, 3, &RAM);
    printf("%lu%c\n", RAM, symbol[unit]); // output is 12G
}
0
CyrIng 15 déc. 2017 à 15:19

Que diriez-vous d'une récursivité:

private static string ReturnSize(double size, string sizeLabel)
{
  if (size > 1024)
  {
    if (sizeLabel.Length == 0)
      return ReturnSize(size / 1024, "KB");
    else if (sizeLabel == "KB")
      return ReturnSize(size / 1024, "MB");
    else if (sizeLabel == "MB")
      return ReturnSize(size / 1024, "GB");
    else if (sizeLabel == "GB")
      return ReturnSize(size / 1024, "TB");
    else
      return ReturnSize(size / 1024, "PB");
  }
  else
  {
    if (sizeLabel.Length > 0)
      return string.Concat(size.ToString("0.00"), sizeLabel);
    else
      return string.Concat(size.ToString("0.00"), "Bytes");
  }
}

Ensuite, vous pouvez l'appeler:

ReturnSize(size, string.Empty);
0
RooiWillie 18 oct. 2017 à 08:07

Je suis allé pour la solution JerKimballs, et bravo à cela. Cependant, je voudrais ajouter / souligner que c'est effectivement un sujet de controverse dans son ensemble. Dans mes recherches (pour d'autres raisons), j'ai trouvé les informations suivantes.

Lorsque des gens normaux (j'ai entendu dire qu'ils existent) parlent de gigaoctets, ils se réfèrent au système métrique dans lequel 1000 à la puissance de 3 à partir du nombre d'origine d'octets == le nombre de gigaoctets. Cependant, bien sûr, il y a les normes IEC / JEDEC qui sont bien résumées dans wikipedia, qui au lieu de 1000 à la puissance de x, ils en ont 1024. Ce qui pour les périphériques de stockage physiques (et je suppose logique comme amazon et autres) signifie un différence toujours croissante entre métrique et CEI. Ainsi, par exemple, 1 To == 1 métrique de téraoctet équivaut à 1 000 pour la puissance de 4, mais la CEI nomme officiellement le nombre similaire à 1 TiB, le tébioctet à 1 024 pour la puissance de 4. Mais, hélas, dans les applications non techniques (je dirais aller par audience) la norme est métrique, et dans ma propre application pour un usage interne, j'explique actuellement la différence de documentation. Mais à des fins d'affichage, je n'offre même rien d'autre que des mesures. En interne, même si ce n'est pas pertinent dans mon application, je ne stocke que des octets et fais le calcul pour l'affichage.

En remarque, je trouve quelque peu terne que le cadre .Net AFAIK (et je me trompe souvent, merci les pouvoirs en place), même dans sa version 4.5, ne contient rien à ce sujet dans les bibliothèques en interne. On pourrait s'attendre à ce qu'une bibliothèque open source quelconque soit NuGettable à un moment donné, mais j'avoue que c'est une petite bête noire. D'un autre côté, System.IO.DriveInfo et d'autres n'ont également que des octets (aussi longs), ce qui est plutôt clair.

0
randomSheeple 13 nov. 2015 à 10:26
    private string GetFileSize(double byteCount)
    {
        string size = "0 Bytes";
        if (byteCount >= 1073741824.0)
            size = String.Format("{0:##.##}", byteCount / 1073741824.0) + " GB";
        else if (byteCount >= 1048576.0)
            size = String.Format("{0:##.##}", byteCount / 1048576.0) + " MB";
        else if (byteCount >= 1024.0)
            size = String.Format("{0:##.##}", byteCount / 1024.0) + " KB";
        else if (byteCount > 0 && byteCount < 1024.0)
            size = byteCount.ToString() + " Bytes";

        return size;
    }

    private void btnBrowse_Click(object sender, EventArgs e)
    {
        if (openFile1.ShowDialog() == DialogResult.OK)
        {
            FileInfo thisFile = new FileInfo(openFile1.FileName);

            string info = "";

            info += "File: " + Path.GetFileName(openFile1.FileName);
            info += Environment.NewLine;
            info += "File Size: " + GetFileSize((int)thisFile.Length);

            label1.Text = info;
        }
    }

C'est aussi une façon de le faire (le nombre 1073741824.0 est de 1024 * 1024 * 1024 aka GB)

4
Lobbe 6 août 2014 à 06:59

J'ai combiné certaines des réponses ici en deux méthodes qui fonctionnent très bien. La deuxième méthode ci-dessous convertira une chaîne d'octets (comme 1,5,1 Go) en octets (comme 1621350140) en tant que valeur de type long. J'espère que cela sera utile à ceux qui recherchent une solution pour convertir des octets en chaîne et les renvoyer en octets.

public static string BytesAsString(float bytes)
{
    string[] suffix = { "B", "KB", "MB", "GB", "TB" };
    int i;
    double doubleBytes = 0;

    for (i = 0; (int)(bytes / 1024) > 0; i++, bytes /= 1024)
    {
        doubleBytes = bytes / 1024.0;
    }

    return string.Format("{0:0.00} {1}", doubleBytes, suffix[i]);
}

public static long StringAsBytes(string bytesString)
{
    if (string.IsNullOrEmpty(bytesString))
    {
        return 0;
    }

    const long OneKb = 1024;
    const long OneMb = OneKb * 1024;
    const long OneGb = OneMb * 1024;
    const long OneTb = OneGb * 1024;
    double returnValue;
    string suffix = string.Empty;

    if (bytesString.IndexOf(" ") > 0)
    {
        returnValue = float.Parse(bytesString.Substring(0, bytesString.IndexOf(" ")));
        suffix = bytesString.Substring(bytesString.IndexOf(" ") + 1).ToUpperInvariant();
    }
    else
    {
        returnValue = float.Parse(bytesString.Substring(0, bytesString.Length - 2));
        suffix = bytesString.ToUpperInvariant().Substring(bytesString.Length - 2);
    }

    switch (suffix)
    {
        case "KB":
            {
                returnValue *= OneKb;
                break;
            }

        case "MB":
            {
                returnValue *= OneMb;
                break;
            }

        case "GB":
            {
                returnValue *= OneGb;
                break;
            }

        case "TB":
            {
                returnValue *= OneTb;
                break;
            }

        default:
            {
                break;
            }
    }

    return Convert.ToInt64(returnValue);
}
1
mesterak 30 oct. 2013 à 05:24

Non, principalement parce qu'il s'agit d'un besoin plutôt spécifique et qu'il existe trop de variations possibles. (Est-ce "KB", "Kb" ou "Ko"? Est-ce un mégaoctet 1024 * 1024 octets, ou 1024 * 1000 octets? - oui, certains endroits l'utilisent!)

5
James Curran 23 janv. 2013 à 20:33

Puisque tout le monde publie ses méthodes, je me suis dit que je publierais la méthode d'extension que j'utilise habituellement pour cela:

EDIT: ajout de variantes int / long ... et correction d'une faute de frappe copypasta ...

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;
    }
}
35
JerKimball 23 janv. 2013 à 20:49

Voici une option plus facile à étendre que la vôtre, mais non, aucune n'est intégrée à la bibliothèque elle-même.

private static List<string> suffixes = new List<string> { " B", " KB", " MB", " GB", " TB", " PB" };
public static string Foo(int number)
{
    for (int i = 0; i < suffixes.Count; i++)
    {
        int temp = number / (int)Math.Pow(1024, i + 1);
        if (temp == 0)
            return (number / (int)Math.Pow(1024, i)) + suffixes[i];
    }
    return number.ToString();
}
5
Servy 23 janv. 2013 à 20:45

https://github.com/logary/logary/blob/master/src/Logary/DataModel.fs#L832-L837

let scaleBytes (value : float) : float * string =
    let log2 x = log x / log 2.
    let prefixes = [| ""; "Ki"; "Mi"; "Gi"; "Ti"; "Pi" |] // note the capital K and the 'i'
    let index = int (log2 value) / 10
    1. / 2.**(float index * 10.),
sprintf "%s%s" prefixes.[index] (Units.symbol Bytes)
0
Henrik 12 déc. 2016 à 17:50

Non.

Mais vous pouvez implémenter comme ceci;

    static double ConvertBytesToMegabytes(long bytes)
    {
    return (bytes / 1024f) / 1024f;
    }

    static double ConvertKilobytesToMegabytes(long kilobytes)
    {
    return kilobytes / 1024f;
    }

Consultez également Comment convertir correctement la taille des fichiers en octets en méga ou gigaoctets?

1
Community 23 mai 2017 à 11:47

Que diriez-vous:

public void printMB(uint sizekB)   
{
    double sizeMB = (double) sizekB / 1024;
    Console.WriteLine("Size is " + sizeMB.ToString("0.00") + "MB");
}

Par exemple. appeler comme

printMB(123456);

Se traduira par une sortie

"Size is 120,56 MB"
0
Boern 7 mai 2014 à 10:55

Basé sur la solution élégante de NeverHopeless:

private static readonly KeyValuePair<long, string>[] Thresholds = 
{
    // new KeyValuePair<long, string>(0, " Bytes"), // Don't devide by Zero!
    new KeyValuePair<long, string>(1, " Byte"),
    new KeyValuePair<long, string>(2, " Bytes"),
    new KeyValuePair<long, string>(1024, " KB"),
    new KeyValuePair<long, string>(1048576, " MB"), // Note: 1024 ^ 2 = 1026 (xor operator)
    new KeyValuePair<long, string>(1073741824, " GB"),
    new KeyValuePair<long, string>(1099511627776, " TB"),
    new KeyValuePair<long, string>(1125899906842620, " PB"),
    new KeyValuePair<long, string>(1152921504606850000, " EB"),

    // These don't fit into a int64
    // new KeyValuePair<long, string>(1180591620717410000000, " ZB"), 
    // new KeyValuePair<long, string>(1208925819614630000000000, " YB") 
};

/// <summary>
/// Returns x Bytes, kB, Mb, etc... 
/// </summary>
public static string ToByteSize(this long value)
{
    if (value == 0) return "0 Bytes"; // zero is plural
    for (int t = Thresholds.Length - 1; t > 0; t--)
        if (value >= Thresholds[t].Key) return ((double)value / Thresholds[t].Key).ToString("0.00") + Thresholds[t].Value;
    return "-" + ToByteSize(-value); // negative bytes (common case optimised to the end of this routine)
}

Il y a peut-être des commentaires excessifs, mais j'ai tendance à les laisser pour m'empêcher de refaire les mêmes erreurs lors des prochaines visites ...

3
Louis Somers 9 févr. 2018 à 14:06
public static class MyExtension
{
    public static string ToPrettySize(this float Size)
    {
        return ConvertToPrettySize(Size, 0);
    }
    public static string ToPrettySize(this int Size)
    {
        return ConvertToPrettySize(Size, 0);
    }
    private static string ConvertToPrettySize(float Size, int R)
    {
        float F = Size / 1024f;
        if (F < 1)
        {
            switch (R)
            {
                case 0:
                    return string.Format("{0:0.00} byte", Size);
                case 1:
                    return string.Format("{0:0.00} kb", Size);
                case 2:
                    return string.Format("{0:0.00} mb", Size);
                case 3:
                    return string.Format("{0:0.00} gb", Size);
            }
        }
        return ConvertToPrettySize(F, ++R);
    }
}
0
PhucNG 12 oct. 2017 à 03:20

Je le résoudrais en utilisant Extension methods, la fonction Math.Pow et 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");
    }
}

et l'utiliser comme:

string h = x.ToSize(MyExtension.SizeUnits.KB);
25
NeverHopeless 29 mars 2014 à 16:32

La version courte de la réponse la plus votée a des problèmes avec les valeurs TB.

Je l'ai ajusté de manière appropriée pour gérer également les valeurs tb et toujours sans boucle et j'ai également ajouté une petite erreur de vérification des valeurs négatives. Voici ma solution:

static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };
static string SizeSuffix(long value, int decimalPlaces = 0)
{
    if (value < 0)
    {
        throw new ArgumentException("Bytes should not be negative", "value");
    }
    var mag = (int)Math.Max(0, Math.Log(value, 1024));
    var adjustedSize = Math.Round(value / Math.Pow(1024, mag), decimalPlaces);
    return String.Format("{0} {1}", adjustedSize, SizeSuffixes[mag]);
}
6
Roemer 28 déc. 2013 à 13:39

Voici une façon assez concise de le faire:

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); } 
    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]);
}

Et voici l'implémentation d'origine que j'ai suggérée, qui peut être légèrement plus lente, mais un peu plus facile à suivre:

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

    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));
175
Jasel 13 oct. 2017 à 03:38