Dies ist nicht der effizienteste Weg, aber es ist einfacher zu lesen, wenn Sie nicht mit Protokollmathematik vertraut sind und für die meisten Szenarien schnell genug sein sollten.
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]);
Ich glaube, Sie könnten Math.Log verwenden, um die Reihenfolge zu bestimmen, anstatt eine while-Schleife zu verwenden.
Francois Botha
12
Außerdem beträgt KB 1000 Byte. 1024 Bytes sind KiB .
Constantin
12
@Constantin gut das hängt vom Betriebssystem ab? Windows zählt immer noch 1024 Bytes als 1 KB und 1 MB = 1024 KB. Ich persönlich möchte das KiB aus dem Fenster werfen und einfach alles mit 1024 zählen? ...
Peter
4
@Petoj es hängt nicht vom Betriebssystem ab, die Definition ist OS-unabhängig. Aus 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
Ich bevorzuge den Code, da er schneller zu laufen scheint, aber ich habe ihn leicht modifiziert, um eine unterschiedliche Anzahl von Dezimalstellen zuzulassen. Kleinere Zahlen zeigen besser 2 Dezimalstellen, z. B. 1,38 MB, während größere Zahlen weniger Dezimalstellen erfordern, z. B. 246 KB oder 23,5 KB:
Myke Black,
320
Verwenden von Log, um das Problem zu lösen ....
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];}
Auch in c #, sollte aber ein Kinderspiel sein. Außerdem habe ich zur besseren Lesbarkeit auf 1 Dezimalstelle gerundet.
Bestimmen Sie grundsätzlich die Anzahl der Dezimalstellen in Base 1024 und dividieren Sie diese durch 1024 ^ Dezimalstellen.
Und einige Verwendungs- und Ausgabebeispiele:
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
Bearbeiten: Es wurde darauf hingewiesen, dass ich einen math.floor verpasst habe, also habe ich ihn eingebaut. (Convert.ToInt32 verwendet Rundung, nicht Abschneiden, und deshalb ist Floor erforderlich.) Vielen Dank für den Haken.
Edit2: Es gab einige Kommentare zu negativen Größen und 0-Byte-Größen, daher habe ich aktualisiert, um diese beiden Fälle zu behandeln.
Ich möchte warnen, dass diese Antwort zwar ein kurzer Code ist, aber nicht die am besten optimierte. Ich möchte, dass Sie sich die von @humbads veröffentlichte Methode ansehen. Ich habe Mikrotests durchgeführt und 10 000 000 zufällig generierte Dateigrößen mit beiden Methoden gesendet. Dies führt zu Zahlen, dass seine Methode ~ 30% schneller ist. Ich habe seine Methode jedoch weiter gereinigt (unnötige Aufgaben und Casting). Außerdem habe ich einen Test mit einer negativen Größe durchgeführt (wenn Sie Dateien vergleichen), während die Methode von Humbads dies fehlerfrei verarbeitet. Diese Log-Methode löst eine Ausnahme aus!
IvanL
1
Ja, Sie sollten Math.Abs für negative Größen hinzufügen. Außerdem behandelt der Code den Fall nicht, wenn die Größe genau 0 ist.
Strichpunkt
Math.Abs, Math.Floor, Math.Log, Konvertieren in Ganzzahl, Math.Round, Math.Pow, Math.Sign, Hinzufügen, Multiplizieren, Dividieren? War das nicht eine Menge Mathe, die den Prozessor stark in Mitleidenschaft gezogen hat? Dies ist wahrscheinlich langsamer als @ Humbads Code
Jayson Ragasa
Fehlgeschlagen für double.MaxValue(Platz = 102)
BrunoLM
Funktioniert super! Ersetzen Sie die Math.Round durch Math.Ceiling, um die Funktionsweise von Windows nachzuahmen (zumindest unter Windows 7 Ultimate). Danke noch einmal. Ich mag diese Lösung.
H_He
101
Eine getestete und deutlich optimierte Version der angeforderten Funktion finden Sie hier:
+1! Einfacher und unkomplizierter! Lässt den Prozessor einfach und schneller rechnen!
Jayson Ragasa
Zu Ihrer Information, Sie verwenden den Wert double readable = (i < 0 ? -i : i);nirgendwo, also entfernen Sie ihn. eine weitere Sache, die Besetzung ist redaundat
Royi Namir
Ich habe die Besetzung entfernt, Kommentare hinzugefügt und ein Problem mit dem negativen Vorzeichen behoben.
Humbads
Gute Antwort. Danke, warum nicht einfach benutzen Math.Abs?
Kspearrin
1
(i <0? -i: i) ist ungefähr 15% schneller als Math.Abs. Bei einer Million Anrufen ist Math.Abs auf meinem Computer 0,5 Millisekunden langsamer - 3,2 ms gegenüber 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();}
Ich mag ein Noob sein, aber es ist ein großer Missbrauch, solch gigantische Kanonen als Pinvoke zu verwenden, um diese Ente zu töten.
Bart
27
Verwendet der Explorer dies? Wenn ja, dann sehr nützlich, damit die Leute die Dateigröße, die Sie ihnen zeigen, mit dem übereinstimmen lassen, was der Explorer anzeigt.
Andrew Backer
8
Und eine, die das Rad nicht neu erfindet
Matthew Lock
Sind 11 Zeichen nicht eine konstante Grenze und dafür ein bisschen niedrig? Ich meine, andere Sprachen verwenden möglicherweise mehr Zeichen für das Akronym für die Bytegröße oder andere Formatierungsstile.
Ray
1
@Bart Es dauert eine Weile, bis Noobs die Weisheit darin erlernen: "Wir sollten kleine Effizienzvorteile vergessen, etwa 97% der Zeit: Vorzeitige Optimierung ist die Wurzel allen Übels" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22
Eine weitere Möglichkeit, es zu häuten, ohne Schleifen und mit Unterstützung für negative Größen (sinnvoll für Dinge wie Deltas mit Dateigröße):
Bitte beachten Sie, dass dies für C # 6.0 (2015) geschrieben wurde, sodass für frühere Versionen möglicherweise eine kleine Bearbeitung erforderlich ist.
Gute Antwort. Es sollte ein Problem geben, wenn die Dateigröße zu klein ist. In diesem Fall gibt / 1024 0 zurück. Sie können einen gebrochenen Typ und einen Aufruf Math.Ceilingoder etwas anderes verwenden.
Nawfal
10
Hier ist eine kurze Antwort, die das Gerät automatisch bestimmt.
für alle, die sich fragen, warum es ein oAfter-KMGTPE gibt: Sein Französisch ( byteist octetauf Französisch). Für jede andere Sprache ersetzen Sie einfach odieb
Sie sollten Folgendes überprüfen: while (Größe> = 1024 && s <Suffixe.Length).
TcKs
nein ... eine 64-Bit-Ganzzahl mit Vorzeichen kann nicht über die ZB hinausgehen ... die die Zahlen 2 ^ 70 darstellt.
Bobwienholt
7
Warum also YB eingeben?
Konfigurator
Ich mag diese Antwort am liebsten selbst, aber jeder hier hat wirklich ineffiziente Lösungen eingeführt. Sie sollten "Größe = Größe >> 10" verwenden. Die Verschiebung ist so viel schneller als die Division ... und ich denke, dass es gut ist, die zu haben Es gibt zusätzliche griechische Spezifizierer, da eine bewegliche DLR-Funktion in naher Zukunft nicht die "lange Größe" benötigen würde. Sie könnten sich auf einer 128-Bit-Vektor-CPU oder etwas befinden, das ZB und größer halten kann;)
RandomNickName42
4
Bitshifting war in den Tagen der C-Codierung auf dem Metall effizienter als die Division. Haben Sie einen Perf-Test in .NET durchgeführt, um festzustellen, ob die Bitverschiebung wirklich effizienter ist? Vor nicht allzu langer Zeit habe ich mir den Status des XOR-Swaps angesehen und festgestellt, dass er in .NET tatsächlich langsamer ist als bei Verwendung einer temporären Variablen.
Pete
7
Wenn Sie versuchen, die in der Detailansicht von Windows Explorer angezeigte Größe anzupassen, ist dies der gewünschte Code:
Dies entspricht nicht nur genau dem Explorer, sondern liefert auch die für Sie übersetzten Zeichenfolgen und die Unterschiede in Windows-Versionen (z. B. in Win10, K = 1000 gegenüber früheren Versionen K = 1024).
Dieser Code wird nicht kompiliert. Sie müssen die DLL angeben, von der die Funktion stammt. Der Prototyp der gesamten Funktion klingt also folgendermaßen: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cchBuf ); Lassen Sie mich der Erste sein, der diese Lösung befürwortet. Warum das Rad neu erfinden, wenn das Rad bereits erfunden wurde? Dies ist ein typischer Ansatz aller C # -Programmierer, aber leider erreicht C # nicht alle Ziele, die C ++ erreicht.
TarmoPikaro
Und noch ein Bugfix: Int64.MaxValue erreicht 9.223.372.036.854.775.807, was die Zuweisung einer Puffergröße von 25+ erfordert - ich habe es für alle Fälle auf 32 gerundet (nicht 11 wie im obigen Demo-Code).
TarmoPikaro
Danke @TarmoPikaro. Beim Kopieren aus meinem Arbeitscode habe ich den DllImport verpasst. Erhöhen Sie auch die Puffergröße gemäß Ihrer Empfehlung. Guter Fang!
Metalogic
beeindruckender Ansatz
tbhaxor
Dies zeigt nur die KB-Einheit. Die Idee ist, die größte Einheit je nach Wert anzuzeigen.
jstuardo
5
Mischung aller Lösungen :-)
/// <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
}
Wie die Lösung von @ NET3. Verwenden Sie Shift anstelle von Division, um den Bereich von zu testen bytes, da Division mehr CPU-Kosten verursacht.
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]);}
Ich nehme an, Sie suchen nach "1,4 MB" anstelle von "1468006 Bytes"?
Ich glaube nicht, dass es in .NET eine integrierte Möglichkeit gibt, dies zu tun. Sie müssen nur herausfinden, welches Gerät geeignet ist, und es formatieren.
Bearbeiten: Hier ist ein Beispielcode, um genau das zu tun:
Da diese Funktionen zu Präsentationszwecken dienen, sollte eine Kultur bereitgestellt werden, zum Beispiel: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
Ein Kilobyte bedeutet 1000 Bytes ( wolframalpha.com/input/?i=kilobyte ), es hängt nicht vom Kontext ab. Es hing historisch vom Kontext ab, wie Wikipedia sagt, und es wurde de jure 1998 geändert und de facto begann die Änderung um 2005, als Terabyte-Festplatten es der Öffentlichkeit bekannt machten. Der Begriff für 1024 Bytes ist Kibibyte. Code, der sie basierend auf der Kultur wechselt, erzeugt falsche Informationen.
Superbest
1
Noch ein Ansatz für das, was es wert ist. Ich mochte die oben erwähnte optimierte @ humbads-Lösung, habe also das Prinzip kopiert, aber ich habe es etwas anders implementiert.
Ich nehme an, es ist fraglich, ob es eine Erweiterungsmethode sein sollte (da nicht alle Longs notwendigerweise Byte-Größen haben), aber ich mag sie und es ist irgendwo, wo ich die Methode finden kann, wenn ich sie das nächste Mal brauche!
In Bezug auf die Einheiten glaube ich nicht, dass ich jemals in meinem Leben "Kibibyte" oder "Mebibyte" gesagt habe, und obwohl ich skeptisch gegenüber solchen erzwungenen und nicht weiterentwickelten Standards bin, denke ich, dass dies langfristig Verwirrung vermeiden wird .
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);}}
Ich verwende die Long- Erweiterungsmethode unten, um sie in eine von Menschen lesbare Größenzeichenfolge zu konvertieren. Diese Methode ist die C # -Implementierung der Java-Lösung derselben Frage, die hier im Stapelüberlauf veröffentlicht wurde .
/// <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";}
Antworten:
Dies ist nicht der effizienteste Weg, aber es ist einfacher zu lesen, wenn Sie nicht mit Protokollmathematik vertraut sind und für die meisten Szenarien schnell genug sein sollten.
quelle
The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
Verwenden von Log, um das Problem zu lösen ....
Auch in c #, sollte aber ein Kinderspiel sein. Außerdem habe ich zur besseren Lesbarkeit auf 1 Dezimalstelle gerundet.
Bestimmen Sie grundsätzlich die Anzahl der Dezimalstellen in Base 1024 und dividieren Sie diese durch 1024 ^ Dezimalstellen.
Und einige Verwendungs- und Ausgabebeispiele:
Bearbeiten: Es wurde darauf hingewiesen, dass ich einen math.floor verpasst habe, also habe ich ihn eingebaut. (Convert.ToInt32 verwendet Rundung, nicht Abschneiden, und deshalb ist Floor erforderlich.) Vielen Dank für den Haken.
Edit2: Es gab einige Kommentare zu negativen Größen und 0-Byte-Größen, daher habe ich aktualisiert, um diese beiden Fälle zu behandeln.
quelle
double.MaxValue
(Platz = 102)Eine getestete und deutlich optimierte Version der angeforderten Funktion finden Sie hier:
C # Human Readable File Size - Optimierte Funktion
Quellcode:
quelle
double readable = (i < 0 ? -i : i);
nirgendwo, also entfernen Sie ihn. eine weitere Sache, die Besetzung ist redaundatMath.Abs
?Von: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html
quelle
Eine weitere Möglichkeit, es zu häuten, ohne Schleifen und mit Unterstützung für negative Größen (sinnvoll für Dinge wie Deltas mit Dateigröße):
Und hier ist die Testsuite:
quelle
Überprüfen Sie die ByteSize- Bibliothek. Es ist das
System.TimeSpan
für Bytes!Es übernimmt die Konvertierung und Formatierung für Sie.
Es werden auch Zeichenfolgen dargestellt und analysiert.
quelle
Ich verwende gerne die folgende Methode (sie unterstützt bis zu Terabyte, was für die meisten Fälle ausreicht, aber leicht erweitert werden kann):
Bitte beachten Sie, dass dies für C # 6.0 (2015) geschrieben wurde, sodass für frühere Versionen möglicherweise eine kleine Bearbeitung erforderlich ist.
quelle
quelle
Math.Ceiling
oder etwas anderes verwenden.Hier ist eine kurze Antwort, die das Gerät automatisch bestimmt.
"b" steht für Bit, "B" steht für Byte und "KMGTPEZY" steht für Kilo, Mega, Giga, Tera, Peta, Exa, Zetta und Yotta
Man kann es erweitern, um ISO / IEC80000 zu berücksichtigen:
quelle
o
After-KMGTPE gibt: Sein Französisch (byte
istoctet
auf Französisch). Für jede andere Sprache ersetzen Sie einfacho
dieb
quelle
Wenn Sie versuchen, die in der Detailansicht von Windows Explorer angezeigte Größe anzupassen, ist dies der gewünschte Code:
Dies entspricht nicht nur genau dem Explorer, sondern liefert auch die für Sie übersetzten Zeichenfolgen und die Unterschiede in Windows-Versionen (z. B. in Win10, K = 1000 gegenüber früheren Versionen K = 1024).
quelle
Mischung aller Lösungen :-)
quelle
Es gibt ein Open Source-Projekt, das das und noch viel mehr kann.
http://humanizr.net/#bytesize
https://github.com/MehdiK/Humanizer
quelle
Wie die Lösung von @ NET3. Verwenden Sie Shift anstelle von Division, um den Bereich von zu testen
bytes
, da Division mehr CPU-Kosten verursacht.quelle
Ich nehme an, Sie suchen nach "1,4 MB" anstelle von "1468006 Bytes"?
Ich glaube nicht, dass es in .NET eine integrierte Möglichkeit gibt, dies zu tun. Sie müssen nur herausfinden, welches Gerät geeignet ist, und es formatieren.
Bearbeiten: Hier ist ein Beispielcode, um genau das zu tun:
http://www.codeproject.com/KB/cpp/formatsize.aspx
quelle
Wie wäre es mit einer Rekursion:
Dann nennst du es:
quelle
Meine 2 Cent:
string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
quelle
Noch ein Ansatz für das, was es wert ist. Ich mochte die oben erwähnte optimierte @ humbads-Lösung, habe also das Prinzip kopiert, aber ich habe es etwas anders implementiert.
Ich nehme an, es ist fraglich, ob es eine Erweiterungsmethode sein sollte (da nicht alle Longs notwendigerweise Byte-Größen haben), aber ich mag sie und es ist irgendwo, wo ich die Methode finden kann, wenn ich sie das nächste Mal brauche!
In Bezug auf die Einheiten glaube ich nicht, dass ich jemals in meinem Leben "Kibibyte" oder "Mebibyte" gesagt habe, und obwohl ich skeptisch gegenüber solchen erzwungenen und nicht weiterentwickelten Standards bin, denke ich, dass dies langfristig Verwirrung vermeiden wird .
quelle
Ich verwende die Long- Erweiterungsmethode unten, um sie in eine von Menschen lesbare Größenzeichenfolge zu konvertieren. Diese Methode ist die C # -Implementierung der Java-Lösung derselben Frage, die hier im Stapelüberlauf veröffentlicht wurde .
quelle