Je me demande si .NET fournit un moyen propre de faire cela:
int64 x = 1000000; ssortingng y = null; if (x / 1024 == 0) { y = x + " bytes"; } else if (x / (1024 * 1024) == 0) { y = ssortingng.Format("{0:n1} KB", x / 1024f); }
etc…
Voici un moyen assez concis de le faire:
static readonly ssortingng[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static ssortingng 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) // [ie 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 ssortingng.Format("{0:n" + decimalPlaces + "} {1}", adjustedSize, SizeSuffixes[mag]); }
Et voici l’implémentation initiale que j’ai suggérée, qui peut être légèrement plus lente, mais un peu plus facile à suivre:
static readonly ssortingng[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static ssortingng 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 ssortingng.Format("{0:n" + decimalPlaces + "} {1}", dValue, SizeSuffixes[i]); } Console.WriteLine(SizeSuffix(100005000L));
Extraire la bibliothèque ByteSize . C’est le System.TimeSpan
pour les octets!
Il gère la conversion et le formatage pour vous.
var maxFileSize = ByteSize.FromKiloBytes(10); maxFileSize.Bytes; maxFileSize.MegaBytes; maxFileSize.GigaBytes;
Il fait également la représentation et l’parsing syntaxique des chaînes.
// ToSsortingng ByteSize.FromKiloBytes(1024).ToSsortingng(); // 1 MB ByteSize.FromGigabytes(.5).ToSsortingng(); // 512 MB ByteSize.FromGigabytes(1024).ToSsortingng(); // 1 TB // Parsing ByteSize.Parse("5b"); ByteSize.Parse("1.55B");
Puisque tout le monde publie ses méthodes, je me suis dit que je posterais la méthode d’extension que j’utilise habituellement pour cela:
EDIT: ajout de variantes int / long … et correction d’une erreur typographique …
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 ssortingng ToPrettySize(this int value, int decimalPlaces = 0) { return ((long)value).ToPrettySize(decimalPlaces); } public static ssortingng 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); ssortingng chosenValue = asTb > 1 ? ssortingng.Format("{0}Tb",asTb) : asGb > 1 ? ssortingng.Format("{0}Gb",asGb) : asMb > 1 ? ssortingng.Format("{0}Mb",asMb) : asKb > 1 ? ssortingng.Format("{0}Kb",asKb) : ssortingng.Format("{0}B", Math.Round((double)value, decimalPlaces)); return chosenValue; } }
Je le résoudrais en utilisant les Extension methods
, la fonction Enums
et Enums
:
public static class MyExtension { public enum SizeUnits { Byte, KB, MB, GB, TB, PB, EB, ZB, YB } public static ssortingng ToSize(this Int64 value, SizeUnits unit) { return (value / (double)Math.Pow(1024, (Int64)unit)).ToSsortingng("0.00"); } }
et l’utiliser comme:
ssortingng h = x.ToSize(MyExtension.SizeUnits.KB);
Non. Principalement parce qu’il s’agit d’un besoin plutôt niche, et qu’il ya trop de variations possibles. (Est-ce “KB”, “Kb” ou “Ko”? Est-ce qu’un mégaoctet 1024 * 1024 octets, ou 1024 * 1000 octets? – oui, certains endroits l’utilisent!)
Voici une option plus facile à étendre que la vôtre, mais non, il n’y en a pas dans la bibliothèque elle-même.
private static List suffixes = new List { " B", " KB", " MB", " GB", " TB", " PB" }; public static ssortingng 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(); }
La version courte de la réponse la plus votée présente des problèmes avec les valeurs de la tuberculose.
Je l’ai ajusté de manière appropriée pour gérer également les valeurs de tb et toujours sans boucle et j’ai également ajouté un peu de vérification des erreurs pour les valeurs négatives. Voici ma solution:
static readonly ssortingng[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; static ssortingng 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]); }
private ssortingng GetFileSize(double byteCount) { ssortingng size = "0 Bytes"; if (byteCount >= 1073741824.0) size = Ssortingng.Format("{0:##.##}", byteCount / 1073741824.0) + " GB"; else if (byteCount >= 1048576.0) size = Ssortingng.Format("{0:##.##}", byteCount / 1048576.0) + " MB"; else if (byteCount >= 1024.0) size = Ssortingng.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 une façon de le faire aussi (le numéro 1073741824.0 est de 1024 * 1024 * 1024 aka GB)
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 est utile pour ceux qui recherchent une solution pour convertir des octets en chaîne et les reconvertir en octets.
public static ssortingng BytesAsSsortingng(float bytes) { ssortingng[] 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 ssortingng.Format("{0:0.00} {1}", doubleBytes, suffix[i]); } public static long SsortingngAsBytes(ssortingng bytesSsortingng) { if (ssortingng.IsNullOrEmpty(bytesSsortingng)) { return 0; } const long OneKb = 1024; const long OneMb = OneKb * 1024; const long OneGb = OneMb * 1024; const long OneTb = OneGb * 1024; double returnValue; ssortingng suffix = ssortingng.Empty; if (bytesSsortingng.IndexOf(" ") > 0) { returnValue = float.Parse(bytesSsortingng.Subssortingng(0, bytesSsortingng.IndexOf(" "))); suffix = bytesSsortingng.Subssortingng(bytesSsortingng.IndexOf(" ") + 1).ToUpperInvariant(); } else { returnValue = float.Parse(bytesSsortingng.Subssortingng(0, bytesSsortingng.Length - 2)); suffix = bytesSsortingng.ToUpperInvariant().Subssortingng(bytesSsortingng.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); }
Basé sur la solution élégante de NeverHopeless:
private static readonly KeyValuePair[] Thresholds = { // new KeyValuePair(0, " Bytes"), // Don't devide by Zero! new KeyValuePair(1, " Byte"), new KeyValuePair(2, " Bytes"), new KeyValuePair(1024, " KB"), new KeyValuePair(1048576, " MB"), // Note: 1024 ^ 2 = 1026 (xor operator) new KeyValuePair(1073741824, " GB"), new KeyValuePair(1099511627776, " TB"), new KeyValuePair(1125899906842620, " PB"), new KeyValuePair(1152921504606850000, " EB"), // These don't fit into a int64 // new KeyValuePair(1180591620717410000000, " ZB"), // new KeyValuePair(1208925819614630000000000, " YB") }; /// /// Returns x Bytes, kB, Mb, etc... /// public static ssortingng 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).ToSsortingng("0.00") + Thresholds[t].Value; return "-" + ToByteSize(-value); // negative bytes (common case optimised to the end of this routine) }
Peut-être y a-t-il des commentaires excessifs, mais j’ai tendance à les laisser pour éviter de faire les mêmes erreurs lors de futures visites …
Non.
Mais vous pouvez mettre en œuvre comme ça;
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?
Que diriez-vous:
public void printMB(uint sizekB) { double sizeMB = (double) sizekB / 1024; Console.WriteLine("Size is " + sizeMB.ToSsortingng("0.00") + "MB"); }
Par exemple, appeler comme
printMB(123456);
Entraînera une sortie
"Size is 120,56 MB"
Je suis allé pour la solution de JerKimballs, et bravo à cela. Cependant, je voudrais append / souligner que c’est effectivement une question de controverse dans son ensemble. Dans mes recherches (pour d’autres raisons), j’ai trouvé les informations suivantes.
Quand des personnes normales (j’ai entendu dire qu’elles existent) parlent de gigaoctets, elles font référence au système mésortingque dans lequel 1000 à la puissance de 3 du nombre d’octets d’origine == 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 ont 1024. Qui pour les périphériques de stockage physique (et je suppose logique comme amazon et autres) signifie différence toujours croissante entre mésortingque et IEC. Donc, par exemple, 1 TB == 1 téraoctet mésortingque est 1000 à la puissance de 4, mais la CEI désigne officiellement un nombre similaire à 1 TiB, tebibyte à 1024 à la puissance de 4. Mais, hélas, dans des applications non techniques aller par public) la norme est mésortingque, et dans ma propre application pour un usage interne, je vous explique la différence de documentation. Mais à des fins d’affichage, je n’offre même que des mésortingques. En interne, même si ce n’est pas pertinent dans mon application, je ne stocke que des octets et effectue le calcul pour l’affichage.
En tant que note d’accompagnement, je trouve un peu terne que le framework .Net AFAIK (et je me trompe souvent grâce aux pouvoirs), 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 de quelque sorte soit NuGettable à un moment donné, mais je reconnais que c’est une petite bête noire. D’autre part, System.IO.DriveInfo et d’autres n’ont que des octets (aussi longs), ce qui est plutôt clair.
https://github.com/logary/logary/blob/master/src/Logary/DataModel.fs#L832-L837
let scaleBytes (value : float) : float * ssortingng = 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)
public static class MyExtension { public static ssortingng ToPrettySize(this float Size) { return ConvertToPrettySize(Size, 0); } public static ssortingng ToPrettySize(this int Size) { return ConvertToPrettySize(Size, 0); } private static ssortingng 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); } }
Que diriez-vous d’une récursivité:
private static ssortingng ReturnSize(double size, ssortingng 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 ssortingng.Concat(size.ToSsortingng("0.00"), sizeLabel); else return ssortingng.Concat(size.ToSsortingng("0.00"), "Bytes"); } }
Ensuite, vous pouvez l’appeler:
ReturnSize(size, ssortingng.Empty);
Comme indiqué ci-dessus, la récursivité est la voie préférée, à 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); }
Maintenant, convertissons 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 }
La réponse de @ Servy était sympa et succincte. Je pense que cela peut être encore plus simple?
private static ssortingng[] suffixes = new [] { " B", " KB", " MB", " GB", " TB", " PB" }; public static ssortingng 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]; }
Je l’utilise pour Windows (préfixes binarys):
static readonly ssortingng[] BinaryPrefix = { "bytes", "KB", "MB", "GB", "TB" }; // , "PB", "EB", "ZB", "YB" ssortingng GetMemorySsortingng(double bytes) { int counter = 0; double value = bytes; ssortingng text = ""; do { text = value.ToSsortingng("0.0") + " " + BinaryPrefix[counter]; value /= 1024; counter++; } while (Math.Floor(value) > 0 && counter < BinaryPrefix.Length); return text; }