Ce n'est pas le moyen le plus efficace de le faire, mais il est plus facile à lire si vous n'êtes pas familier avec les mathématiques des journaux et devrait être assez rapide pour la plupart des scénarios.
string[] sizes ={"B","KB","MB","GB","TB"};double len =newFileInfo(filename).Length;int order =0;while(len >=1024&& order < sizes.Length-1){
order++;
len = len/1024;}// Adjust the format string to your preferences. For example "{0:0.#}{1}" would// show a single decimal place, and no space.string result =String.Format("{0:0.##} {1}", len, sizes[order]);
Je pense que vous pouvez utiliser Math.Log pour déterminer l'ordre au lieu d'utiliser une boucle while.
Francois Botha
12
En outre, KB est de 1000 octets. 1024 octets est KiB .
Constantin
13
@Constantin ça dépend bien de l'OS? Windows compte toujours 1024 octets comme 1 Ko et 1 Mo = 1024 Ko. Personnellement, je veux jeter le KiB par la fenêtre et compter tout en utilisant 1024? ...
Peter
4
@Petoj cela ne dépend pas du système d'exploitation, la définition est indépendante du système d'exploitation. De Wikipedia:The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
ANeves
3
Je préfère ce code car il semble fonctionner plus rapidement mais je l'ai légèrement modifié pour permettre différents nombres de décimales. Les petits nombres affichent mieux 2 décimales, par exemple 1,38 Mo, tandis que les grands nombres nécessitent moins de décimales, par exemple 246 Ko ou 23,5 Ko:
Myke Black
321
utiliser Log pour résoudre le problème ....
staticStringBytesToString(long byteCount){string[] suf ={"B","KB","MB","GB","TB","PB","EB"};//Longs run out around EBif(byteCount ==0)return"0"+ suf[0];long bytes =Math.Abs(byteCount);int place =Convert.ToInt32(Math.Floor(Math.Log(bytes,1024)));double num =Math.Round(bytes /Math.Pow(1024, place),1);return(Math.Sign(byteCount)* num).ToString()+ suf[place];}
Également en c #, mais devrait être un composant logiciel enfichable à convertir. J'ai également arrondi à 1 décimale pour plus de lisibilité.
Fondamentalement, déterminez le nombre de décimales dans Base 1024, puis divisez par 1024 ^ décimales.
Et quelques exemples d'utilisation et de sortie:
Console.WriteLine(BytesToString(9223372036854775807));//Results in 8EBConsole.WriteLine(BytesToString(0));//Results in 0BConsole.WriteLine(BytesToString(1024));//Results in 1KBConsole.WriteLine(BytesToString(2000000));//Results in 1.9MBConsole.WriteLine(BytesToString(-9023372036854775807));//Results in -7.8EB
Edit: On m'a fait remarquer que j'avais raté un plancher mathématique, alors je l'ai incorporé. (Convert.ToInt32 utilise l'arrondi, pas la troncature et c'est pourquoi Floor est nécessaire.) Merci pour la capture.
Edit2: Il y avait quelques commentaires sur les tailles négatives et les tailles 0 octet, j'ai donc mis à jour pour gérer ces 2 cas.
Je tiens à avertir que bien que cette réponse soit en effet un court morceau de code, elle n'est pas la plus optimisée. J'aimerais que vous jetiez un œil à la méthode publiée par @humbads. J'ai effectué des microtests en envoyant 10 000 000 de tailles de fichiers générées aléatoirement via les deux méthodes, ce qui fait apparaître que sa méthode est ~ 30% plus rapide. J'ai cependant fait un peu de nettoyage supplémentaire de sa méthode (missions et casting non nécessaires). De plus, j'ai effectué un test avec une taille négative (lorsque vous comparez des fichiers) tandis que la méthode des humbads traite parfaitement cette méthode Log qui lèvera une exception!
IvanL
1
Oui, vous devez ajouter Math.Abs pour les tailles négatives. De plus, le code ne gère pas le cas si la taille est exactement 0.
dasheddot
Math.Abs, Math.Floor, Math.Log, Conversion en entier, Math.Round, Math.Pow, Math.Sign, Ajout, Multiplication, Division? N'était-ce pas cette tonne de maths qui faisait juste un énorme pic sur le processeur. C'est probablement plus lent que le code @humbads
Jayson Ragasa
Échoue pour double.MaxValue(place = 102)
BrunoLM
Fonctionne très bien! Pour imiter le fonctionnement de Windows (au moins sur mon Windows 7 Ultimate), remplacez Math.Round par Math.Ceiling. Merci encore. J'aime cette solution.
H_He
101
Une version testée et considérablement optimisée de la fonction demandée est publiée ici:
+1! Plus simple et direct! Permet au processeur de faire le calcul facilement et plus rapidement!
Jayson Ragasa
Pour info, vous n'utilisez la valeur double readable = (i < 0 ? -i : i);nulle part, donc supprimez-la. une dernière chose, le casting est redaundat
Royi Namir
J'ai supprimé la distribution, ajouté des commentaires et résolu un problème avec le signe négatif.
humbads
Très bonne réponse. Merci, pourquoi ne pas simplement utiliser Math.Abs?
kspearrin
1
(i <0? -i: i) est environ 15% plus rapide que Math.Abs. Pour un million d'appels, Math.Abs est 0,5 millisecondes plus lent sur ma machine - 3,2 ms contre 3,7 ms.
humbads
72
[DllImport("Shlwapi.dll",CharSet=CharSet.Auto)]publicstaticexternlongStrFormatByteSize(long fileSize
,[MarshalAs(UnmanagedType.LPTStr)]StringBuilder buffer
,int bufferSize );/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes, kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="filelength">The numeric value to be converted.</param>/// <returns>the converted string</returns>publicstaticstringStrFormatByteSize(long filesize){StringBuilder sb =newStringBuilder(11);StrFormatByteSize( filesize, sb, sb.Capacity);return sb.ToString();}
Je suis peut-être un noob, mais utiliser un canon aussi gigantesque que pinvoke pour tuer ce canard est une mauvaise utilisation.
Bart
27
Est-ce ce que l'explorateur utilise? Si oui, alors magnifiquement utile pour permettre aux gens de faire correspondre la taille du fichier que vous leur montrez avec ce que l'explorateur montre.
Andrew Backer
8
Et celui qui ne réinvente pas la roue
Matthew Lock
N'est-ce pas 11 caractères une limite constante et un peu faible pour cela? Je veux dire, d'autres langues peuvent utiliser plus de caractères pour l'acronyme de taille d'octet ou d'autres styles de formatage.
Ray
1
@Bart il faut un certain temps aux noobs pour apprendre la sagesse en ceci: "Nous devons oublier les petites efficacités, disons environ 97% du temps: l'optimisation prématurée est la racine de tout mal" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22
Une autre façon de l'habiller, sans aucune sorte de boucles et avec un support de taille négative (est logique pour des choses comme les deltas de taille de fichier):
Pas de honte dans une bibliothèque pratique comme celle-ci. :-)
Larsenal
13
J'aime utiliser la méthode suivante (elle prend en charge jusqu'à téraoctets, ce qui est suffisant dans la plupart des cas, mais elle peut facilement être étendue):
Veuillez garder à l'esprit que cela est écrit pour C # 6.0 (2015), donc il pourrait avoir besoin d'un peu de modification pour les versions antérieures.
Bonne réponse. Il devrait y avoir un problème lorsque la taille du fichier est trop petite, auquel cas / 1024 renvoie 0. Vous pouvez utiliser un type fractionnaire et appeler Math.Ceilingou quelque chose.
nawfal
10
Voici une réponse concise qui détermine automatiquement l'unité.
"b" est pour le bit, "B" est pour l'octet et "KMGTPEZY" sont respectivement pour le kilo, le méga, le giga, le tera, le peta, l'exa, le zetta et le yotta
On peut l'étendre pour prendre en compte ISO / IEC80000 :
pour tout le monde demande pourquoi il y a un oaprès KMGTPE: Son français ( byteest octeten français). Pour toute autre langue, remplacez simplement le oparb
Vous devez vérifier: while (size> = 1024 && s <suffixes.Length).
TcKs
non ... un entier signé 64 bits ne peut pas dépasser le ZB ... qui représente les nombres 2 ^ 70.
bobwienholt
7
Alors pourquoi mettre YB?
configurateur
J'aime mieux cette réponse moi-même, mais tout le monde ici propose des solutions vraiment inefficaces, vous devriez utiliser "size = size >> 10", le décalage est donc beaucoup plus rapide que la division ... et je pense que c'est bien d'avoir le un spécificateur grec supplémentaire est là, car dans un avenir proche, une fonction DLR posiable n'aurait pas besoin de la "taille longue .." vous pourriez être sur un processeur vectoriel 128 bits ou quelque chose qui peut contenir ZB et plus grand;)
RandomNickName42
4
Le bitshifting était plus efficace que la division à l'époque du codage C sur le métal. Avez-vous fait un test de perf dans .NET pour voir si le décalage est vraiment plus efficace? Il n'y a pas si longtemps, j'ai regardé l'état du xor-swap et j'ai trouvé qu'il était en fait plus lent dans .NET qu'avec une variable temporaire.
Pete
7
Si vous essayez de faire correspondre la taille comme indiqué dans la vue détaillée de l'Explorateur Windows, voici le code que vous souhaitez:
Cela correspondra non seulement à l'Explorateur, mais fournira également les chaînes traduites pour vous et correspondra aux différences dans les versions de Windows (par exemple dans Win10, K = 1000 par rapport aux versions précédentes K = 1024).
Ce code ne se compile pas, vous devez spécifier la DLL d'où provient la fonction. Ainsi, le prototype de la fonction entière ressemble à ceci: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static external long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBufuf ); Permettez-moi d'être le premier à favoriser cette solution. Pourquoi réinventer la roue si la roue a déjà été inventée? C'est l'approche typique de tous les programmeurs C #, mais malheureusement C # n'atteint pas toutes les cibles atteintes par C ++.
TarmoPikaro
Et un autre bugfix: Int64.MaxValue atteint 9.223.372.036.854.775.807, ce qui nécessite d'allouer une taille de tampon de 25+ - je l'ai arrondi à 32 au cas où (pas 11 comme dans le code de démonstration ci-dessus).
TarmoPikaro
Merci @TarmoPikaro. Lorsque j'ai copié à partir de mon code de travail, j'ai raté le DllImport. Également augmenté la taille du tampon selon votre recommandation. Bonne prise!
Metalogic
approche impressionnante
tbhaxor
Cela montre uniquement l'unité KB. L'idée est de montrer la plus grande unité en fonction de la valeur.
jstuardo
5
Mélange de toutes les solutions :-)
/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes,/// kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="fileSize">The numeric value to be converted.</param>/// <returns>The converted string.</returns>publicstaticstringFormatByteSize(double fileSize){FileSizeUnit unit =FileSizeUnit.B;while(fileSize >=1024&& unit <FileSizeUnit.YB){
fileSize = fileSize /1024;
unit++;}returnstring.Format("{0:0.##} {1}", fileSize, unit);}/// <summary>/// Converts a numeric value into a string that represents the number expressed as a size value in bytes,/// kilobytes, megabytes, or gigabytes, depending on the size./// </summary>/// <param name="fileInfo"></param>/// <returns>The converted string.</returns>publicstaticstringFormatByteSize(FileInfo fileInfo){returnFormatByteSize(fileInfo.Length);}}publicenumFileSizeUnit:byte{
B,
KB,
MB,
GB,
TB,
PB,
EB,
ZB,
YB
}
Comme la solution de @ NET3. Utilisez shift au lieu de division pour tester la plage de bytes, car la division prend plus de coûts CPU.
privatestaticreadonlystring[] UNITS =newstring[]{"B","KB","MB","GB","TB","PB","EB"};publicstaticstringFormatSize(ulong bytes){int c =0;for(c =0; c < UNITS.Length; c++){ulong m =(ulong)1<<((c +1)*10);if(bytes < m)break;}double n = bytes /(double)((ulong)1<<(c *10));returnstring.Format("{0:0.##} {1}", n, UNITS[c]);}
Le préfixe pour le kilo-octet est kB (K minuscule)
Étant donné que ces fonctions sont à des fins de présentation, il convient de fournir une culture, par exemple: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
Selon le contexte, un kilo-octet peut être de 1 000 ou 1 024 octets . Il en va de même pour les Mo, les Go, etc.
Un kilo-octet signifie 1000 octets ( wolframalpha.com/input/?i=kilobyte ), cela ne dépend pas du contexte. Il dépendait historiquement du contexte, comme le dit Wikipédia, et il a été de jure changé en 1998 et un changement de facto a commencé vers 2005 lorsque les disques durs de téraoctets l'ont porté à l'attention du public. Le terme pour 1024 octets est kibioctet. Le code qui les change en fonction de la culture produit des informations incorrectes.
Superbe le
1
Une approche de plus, pour ce que ça vaut. J'ai aimé la solution optimisée @humbads référencée ci-dessus, j'ai donc copié le principe, mais je l'ai implémenté un peu différemment.
Je suppose qu'il est discutable de savoir si ce devrait être une méthode d'extension (car tous les longs ne sont pas nécessairement des tailles d'octets), mais je les aime, et c'est quelque part où je peux trouver la méthode lorsque j'en aurai besoin!
En ce qui concerne les unités, je ne pense pas avoir jamais dit «Kibibyte» ou «Mebibyte» dans ma vie, et bien que je sceptique quant à ces normes appliquées plutôt qu'évolues, je suppose que cela évitera la confusion à long terme .
publicstaticclassLongExtensions{privatestaticreadonlylong[] numberOfBytesInUnit;privatestaticreadonlyFunc<long,string>[] bytesToUnitConverters;staticLongExtensions(){
numberOfBytesInUnit =newlong[6]{1L<<10,// Bytes in a Kibibyte1L<<20,// Bytes in a Mebibyte1L<<30,// Bytes in a Gibibyte1L<<40,// Bytes in a Tebibyte1L<<50,// Bytes in a Pebibyte1L<<60// Bytes in a Exbibyte};// Shift the long (integer) down to 1024 times its number of units, convert to a double (real number), // then divide to get the final number of units (units will be in the range 1 to 1023.999)Func<long,int,string>FormatAsProportionOfUnit=(bytes, shift)=>(((double)(bytes >> shift))/1024).ToString("0.###");
bytesToUnitConverters =newFunc<long,string>[7]{
bytes => bytes.ToString()+" B",
bytes =>FormatAsProportionOfUnit(bytes,0)+" KiB",
bytes =>FormatAsProportionOfUnit(bytes,10)+" MiB",
bytes =>FormatAsProportionOfUnit(bytes,20)+" GiB",
bytes =>FormatAsProportionOfUnit(bytes,30)+" TiB",
bytes =>FormatAsProportionOfUnit(bytes,40)+" PiB",
bytes =>FormatAsProportionOfUnit(bytes,50)+" EiB",};}publicstaticstringToReadableByteSizeString(thislong bytes){if(bytes <0)return"-"+Math.Abs(bytes).ToReadableByteSizeString();int counter =0;while(counter < numberOfBytesInUnit.Length){if(bytes < numberOfBytesInUnit[counter])return bytesToUnitConverters[counter](bytes);
counter++;}return bytesToUnitConverters[counter](bytes);}}
J'utilise la méthode d'extension longue ci-dessous pour convertir en une chaîne de taille lisible par l'homme. Cette méthode est l'implémentation C # de la solution Java de cette même question publiée sur Stack Overflow, ici .
/// <summary>/// Convert a byte count into a human readable size string./// </summary>/// <param name="bytes">The byte count.</param>/// <param name="si">Whether or not to use SI units.</param>/// <returns>A human readable size string.</returns>publicstaticstringToHumanReadableByteCount(thislong bytes
,bool si
){var unit = si
?1000:1024;if(bytes < unit){return $"{bytes} B";}var exp =(int)(Math.Log(bytes)/Math.Log(unit));return $"{bytes / Math.Pow(unit, exp):F2} "+
$"{(si ? "kMGTPE" : "KMGTPE")[exp - 1] + (si ? string.Empty : "i")}B";}
Réponses:
Ce n'est pas le moyen le plus efficace de le faire, mais il est plus facile à lire si vous n'êtes pas familier avec les mathématiques des journaux et devrait être assez rapide pour la plupart des scénarios.
la source
The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
utiliser Log pour résoudre le problème ....
Également en c #, mais devrait être un composant logiciel enfichable à convertir. J'ai également arrondi à 1 décimale pour plus de lisibilité.
Fondamentalement, déterminez le nombre de décimales dans Base 1024, puis divisez par 1024 ^ décimales.
Et quelques exemples d'utilisation et de sortie:
Edit: On m'a fait remarquer que j'avais raté un plancher mathématique, alors je l'ai incorporé. (Convert.ToInt32 utilise l'arrondi, pas la troncature et c'est pourquoi Floor est nécessaire.) Merci pour la capture.
Edit2: Il y avait quelques commentaires sur les tailles négatives et les tailles 0 octet, j'ai donc mis à jour pour gérer ces 2 cas.
la source
double.MaxValue
(place = 102)Une version testée et considérablement optimisée de la fonction demandée est publiée ici:
Taille de fichier lisible par l'homme C # - Fonction optimisée
Code source:
la source
double readable = (i < 0 ? -i : i);
nulle part, donc supprimez-la. une dernière chose, le casting est redaundatMath.Abs
?De: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html
la source
Une autre façon de l'habiller, sans aucune sorte de boucles et avec un support de taille négative (est logique pour des choses comme les deltas de taille de fichier):
Et voici la suite de tests:
la source
La caisse ByteSize bibliothèque. C'est pour les
System.TimeSpan
octets!Il gère la conversion et le formatage pour vous.
Il effectue également la représentation et l'analyse des chaînes.
la source
J'aime utiliser la méthode suivante (elle prend en charge jusqu'à téraoctets, ce qui est suffisant dans la plupart des cas, mais elle peut facilement être étendue):
Veuillez garder à l'esprit que cela est écrit pour C # 6.0 (2015), donc il pourrait avoir besoin d'un peu de modification pour les versions antérieures.
la source
la source
Math.Ceiling
ou quelque chose.Voici une réponse concise qui détermine automatiquement l'unité.
"b" est pour le bit, "B" est pour l'octet et "KMGTPEZY" sont respectivement pour le kilo, le méga, le giga, le tera, le peta, l'exa, le zetta et le yotta
On peut l'étendre pour prendre en compte ISO / IEC80000 :
la source
o
après KMGTPE: Son français (byte
estoctet
en français). Pour toute autre langue, remplacez simplement leo
parb
la source
Si vous essayez de faire correspondre la taille comme indiqué dans la vue détaillée de l'Explorateur Windows, voici le code que vous souhaitez:
Cela correspondra non seulement à l'Explorateur, mais fournira également les chaînes traduites pour vous et correspondra aux différences dans les versions de Windows (par exemple dans Win10, K = 1000 par rapport aux versions précédentes K = 1024).
la source
Mélange de toutes les solutions :-)
la source
Il existe un projet open source qui peut le faire et bien plus encore.
http://humanizr.net/#bytesize
https://github.com/MehdiK/Humanizer
la source
Comme la solution de @ NET3. Utilisez shift au lieu de division pour tester la plage de
bytes
, car la division prend plus de coûts CPU.la source
Je suppose que vous recherchez "1,4 Mo" au lieu de "1468006 octets"?
Je ne pense pas qu'il existe un moyen intégré de le faire dans .NET. Vous devrez simplement déterminer quelle unité est appropriée et la formater.
Edit: Voici quelques exemples de code pour faire exactement cela:
http://www.codeproject.com/KB/cpp/formatsize.aspx
la source
Que diriez-vous d'une récursivité:
Ensuite, vous l'appelez:
la source
Mes 2 cents:
string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
la source
Une approche de plus, pour ce que ça vaut. J'ai aimé la solution optimisée @humbads référencée ci-dessus, j'ai donc copié le principe, mais je l'ai implémenté un peu différemment.
Je suppose qu'il est discutable de savoir si ce devrait être une méthode d'extension (car tous les longs ne sont pas nécessairement des tailles d'octets), mais je les aime, et c'est quelque part où je peux trouver la méthode lorsque j'en aurai besoin!
En ce qui concerne les unités, je ne pense pas avoir jamais dit «Kibibyte» ou «Mebibyte» dans ma vie, et bien que je sceptique quant à ces normes appliquées plutôt qu'évolues, je suppose que cela évitera la confusion à long terme .
la source
J'utilise la méthode d'extension longue ci-dessous pour convertir en une chaîne de taille lisible par l'homme. Cette méthode est l'implémentation C # de la solution Java de cette même question publiée sur Stack Overflow, ici .
la source