Ini bukan cara yang paling efisien untuk melakukannya, tetapi lebih mudah dibaca jika Anda tidak terbiasa dengan matematika log, dan harus cukup cepat untuk sebagian besar skenario.
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]);
@Konstantin juga tergantung pada OS? Windows masih menghitung 1024 byte sebagai 1 KB dan 1 MB = 1024 KB, Secara pribadi saya ingin membuang KiB keluar jendela dan hanya menghitung setiap hal menggunakan 1024? ...
Peter
4
@ Petoj itu tidak tergantung pada OS, definisi adalah OS-agnostik. Dari 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
Saya lebih suka kode ini karena tampaknya berjalan lebih cepat tetapi saya memodifikasinya sedikit untuk memungkinkan jumlah tempat desimal yang berbeda. Angka yang lebih kecil lebih baik menunjukkan 2 tempat desimal, misalnya 1,38MB sedangkan angka yang lebih besar membutuhkan desimal yang lebih sedikit misalnya 246k atau 23,5KB:
Myke Black
321
menggunakan Log untuk menyelesaikan masalah ....
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];}
Juga di c #, tetapi harus menjadi snap untuk mengkonversi. Saya juga membulatkan ke 1 tempat desimal untuk dibaca.
Pada dasarnya Tentukan jumlah tempat desimal di Basis 1024 dan kemudian bagi dengan 1024 ^ tempat desimal.
Dan beberapa contoh penggunaan dan keluaran:
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
Sunting: Menunjukkan bahwa saya melewatkan lantai math.for, jadi saya memasukkannya. (Convert.ToInt32 menggunakan pembulatan, tidak memotong dan itu sebabnya Lantai diperlukan.) Terima kasih atas tangkapannya.
Sunting2: Ada beberapa komentar tentang ukuran negatif dan ukuran 0 byte, jadi saya memperbarui untuk menangani 2 kasus itu.
Saya ingin memperingatkan bahwa sementara jawaban ini memang sepotong kode pendek itu bukan yang paling dioptimalkan. Saya ingin Anda melihat metode yang diposting oleh @Humbads. Saya menjalankan microtesting mengirimkan 10 000 000 file yang dihasilkan secara acak melalui kedua metode dan ini menampilkan angka bahwa metodenya ~ 30% lebih cepat. Saya melakukan pembersihan lebih lanjut dari metodenya (penugasan & casting yang tidak khas). Selanjutnya saya menjalankan tes dengan ukuran negatif (ketika Anda membandingkan file) sementara metode humbad dengan sempurna memproses ini, metode Log ini akan melempar pengecualian!
IvanL
1
Yap, Anda harus menambahkan Math.Abs untuk ukuran negatif. Lebih jauh lagi, kode ini tidak menangani casing jika ukurannya tepat 0.
dasheddot
Math.Abs, Math.Floor, Math.Log, Konversi ke integer, Math.Round, Math.Pow, Math.Sign, Menambah, Mengalikan, Membagi? Bukankah ini banyak matematika hanya membuat lonjakan besar pada prosesor. Ini mungkin lebih lambat dari kode @humbads
Jayson Ragasa
Gagal untuk double.MaxValue(tempat = 102)
BrunoLM
Bagus sekali! Untuk meniru cara kerja windows (setidaknya pada ultimate Windows 7 saya), ganti Math.Round dengan Math.Ceiling. Terima kasih lagi. Saya suka solusi ini.
Dia_
101
Versi yang diuji dan dioptimalkan secara signifikan dari fungsi yang diminta diposting di sini:
+1! Lebih sederhana dan lurus ke depan! Membuat prosesor melakukan perhitungan dengan mudah dan cepat!
Jayson Ragasa
FYI, Anda tidak menggunakan nilai di double readable = (i < 0 ? -i : i);mana pun jadi hapus saja. satu hal lagi, pemerannya adalah redaundat
Royi Namir
Saya menghapus para pemain, menambahkan komentar, dan memperbaiki masalah dengan tanda negatif.
humbads
Jawaban yang bagus Terima kasih, Kenapa tidak pakai saja Math.Abs?
kspearrin
1
(i <0? -i: i) sekitar 15% lebih cepat dari Math.Abs. Untuk satu juta panggilan, Math.Abs lebih lambat 0,5 milidetik pada mesin saya - 3,2 ms vs 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();}
Saya mungkin seorang noob, tetapi menggunakan meriam raksasa seperti pinvoke untuk membunuh bebek itu adalah penyalahgunaan besar.
Bart
27
Apakah ini yang digunakan penjelajah? Jika demikian, maka sangat berguna untuk membiarkan orang-orang cocok dengan ukuran file yang Anda perlihatkan kepada mereka dengan apa yang ditampilkan oleh penjelajah.
Andrew Backer
8
Dan yang tidak menemukan kembali roda
Matthew Lock
Bukankah 11 karakter batas konstan dan sedikit rendah untuk itu? Maksudku, bahasa lain mungkin menggunakan lebih banyak karakter untuk akronim ukuran byte, atau gaya pemformatan lainnya.
Ray
1
@Bart, perlu beberapa saat bagi noobs untuk mempelajari kebijaksanaan dalam hal ini: "Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan" ubiquity.acm.org/article.cfm? id = 1513451
Matthew Lock
22
Satu lagi cara untuk mengulitinya, tanpa loop apa pun dan dengan dukungan ukuran negatif (masuk akal untuk hal-hal seperti delta ukuran file):
Jawaban yang bagus. Seharusnya ada masalah ketika ukuran file terlalu kecil, di mana / 1024 mengembalikan 0. Anda bisa menggunakan tipe fraksional dan panggilan Math.Ceilingatau sesuatu.
nawfal
10
Inilah jawaban singkat yang menentukan unit secara otomatis.
Anda harus memeriksa: while (size> = 1024 && s <suffixes.Length).
TcK
tidak ... integer bertanda 64-bit tidak dapat melampaui ZB ... yang mewakili angka 2 ^ 70.
bobwienholt
7
Jadi mengapa dimasukkan ke YB?
konfigurator
Saya suka jawaban ini sendiri, tetapi semua orang di sini memberikan solusi yang benar-benar tidak efisien, Anda harus menggunakan shift "size = size >> 10" jauh lebih cepat daripada pembagian ... dan saya pikir sebaiknya memiliki ekstra Yunani specifier ada di sana, karena dalam waktu dekat, fungsi DLR yang mungkin tidak akan memerlukan "ukuran panjang .." Anda bisa pada cpu vektor 128 bit atau sesuatu yang dapat menampung ZB dan lebih besar;)
RandomNickName42
4
Bitshifting lebih efisien daripada pembagian pada zaman C coding pada logam. Sudahkah Anda melakukan tes perf dalam .NET untuk melihat apakah bitshift benar-benar lebih efisien? Belum lama ini, saya melihat keadaan xor-swap dan menemukan itu sebenarnya lebih lambat di .NET vs menggunakan variabel temp.
Pete
7
Jika Anda mencoba mencocokkan ukuran seperti yang ditunjukkan pada tampilan detail Windows Explorer, ini adalah kode yang Anda inginkan:
Ini tidak hanya cocok dengan Explorer tetapi juga akan memberikan string yang diterjemahkan untuk Anda dan cocok dengan perbedaan dalam versi Windows (misalnya di Win10, K = 1000 vs versi sebelumnya K = 1024).
Kode ini tidak mengkompilasi, Anda perlu menentukan dll dari mana fungsi berasal. Jadi prototipe seluruh fungsi terdengar seperti ini: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern panjang StrFormatKBSize (qdw panjang, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder pszBuf, int cuf ); Biarkan saya menjadi yang pertama yang mendukung solusi ini. Mengapa harus menemukan kembali roda jika roda sudah ditemukan? Ini adalah pendekatan khas semua programmer C #, tetapi sayangnya C # tidak mencapai semua target yang dicapai C ++.
TarmoPikaro
Dan satu lagi perbaikan bug: Int64.MaxValue mencapai 9.223.372.036.854.775.807, yang mengharuskan untuk mengalokasikan ukuran buffer 25+ - Saya telah membulatkannya menjadi 32 untuk berjaga-jaga (tidak 11 seperti dalam kode demo di atas).
TarmoPikaro
Terima kasih @TarmoPikaro. Ketika saya menyalin dari kode kerja saya, saya melewatkan DllImport. Juga meningkatkan ukuran buffer sesuai rekomendasi Anda. Tangkapan yang bagus!
Metalogic
pendekatan yang mengesankan
tbhaxor
Ini hanya menunjukkan unit KB. Idenya adalah untuk menunjukkan unit terbesar tergantung pada nilainya.
jstuardo
5
Campuran semua solusi :-)
/// <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
}
Seperti solusi @ NET3. Gunakan shift alih-alih divisi untuk menguji kisaran bytes, karena pembagian membutuhkan biaya CPU lebih banyak.
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]);}
Karena fungsi-fungsi ini untuk tujuan presentasi, seseorang harus menyediakan budaya, misalnya: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
Bergantung pada konteksnya, satu kilobyte dapat berupa 1000 atau 1024 byte . Hal yang sama berlaku untuk MB, GB, dll.
Satu kilobyte berarti 1000 byte ( wolframalpha.com/input/?i=kilobyte ), itu tidak tergantung pada konteks. Secara historis tergantung pada konteks, seperti kata wikipedia, dan perubahan itu terjadi pada tahun 1998 dan perubahan de facto dimulai sekitar tahun 2005 ketika hard drive terabyte membawanya ke perhatian publik. Istilah untuk 1024 byte adalah kibibyte. Kode yang mengalihkan mereka berdasarkan budaya menghasilkan informasi yang salah.
Biasa
1
Satu lagi pendekatan, untuk apa nilainya. Saya menyukai solusi teroptimalkan @humbads yang dirujuk di atas, jadi telah menyalin prinsipnya, tetapi saya telah menerapkannya sedikit berbeda.
Saya kira itu masih bisa diperdebatkan, apakah itu harus menjadi metode ekstensi (karena tidak semua lama harus ukuran byte), tapi saya suka mereka, dan di suatu tempat saya dapat menemukan metode ketika saya membutuhkannya nanti!
Mengenai unit, saya tidak berpikir saya pernah mengatakan 'Kibibyte' atau 'Mebibyte' dalam hidup saya, dan sementara saya skeptis dengan standar yang ditegakkan daripada berkembang, saya kira itu akan menghindari kebingungan dalam jangka panjang .
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);}}
Saya menggunakan metode ekstensi Panjang di bawah ini untuk mengonversi string ukuran yang dapat dibaca manusia. Metode ini adalah implementasi C # dari solusi Java untuk pertanyaan yang sama yang diposting di Stack Overflow, di sini .
/// <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";}
Jawaban:
Ini bukan cara yang paling efisien untuk melakukannya, tetapi lebih mudah dibaca jika Anda tidak terbiasa dengan matematika log, dan harus cukup cepat untuk sebagian besar skenario.
sumber
The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
menggunakan Log untuk menyelesaikan masalah ....
Juga di c #, tetapi harus menjadi snap untuk mengkonversi. Saya juga membulatkan ke 1 tempat desimal untuk dibaca.
Pada dasarnya Tentukan jumlah tempat desimal di Basis 1024 dan kemudian bagi dengan 1024 ^ tempat desimal.
Dan beberapa contoh penggunaan dan keluaran:
Sunting: Menunjukkan bahwa saya melewatkan lantai math.for, jadi saya memasukkannya. (Convert.ToInt32 menggunakan pembulatan, tidak memotong dan itu sebabnya Lantai diperlukan.) Terima kasih atas tangkapannya.
Sunting2: Ada beberapa komentar tentang ukuran negatif dan ukuran 0 byte, jadi saya memperbarui untuk menangani 2 kasus itu.
sumber
double.MaxValue
(tempat = 102)Versi yang diuji dan dioptimalkan secara signifikan dari fungsi yang diminta diposting di sini:
C # Ukuran File yang Dapat Dibaca Manusia - Fungsi yang Dioptimalkan
Kode sumber:
sumber
double readable = (i < 0 ? -i : i);
mana pun jadi hapus saja. satu hal lagi, pemerannya adalah redaundatMath.Abs
?Dari: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html
sumber
Satu lagi cara untuk mengulitinya, tanpa loop apa pun dan dengan dukungan ukuran negatif (masuk akal untuk hal-hal seperti delta ukuran file):
Dan di sini adalah test suite:
sumber
Periksa perpustakaan ByteSize . Ini
System.TimeSpan
untuk byte!Ini menangani konversi dan pemformatan untuk Anda.
Itu juga melakukan representasi string dan parsing.
sumber
Saya suka menggunakan metode berikut (ini mendukung hingga terabyte, yang cukup untuk sebagian besar kasus, tetapi dapat dengan mudah diperpanjang):
Harap diingat bahwa ini ditulis untuk C # 6.0 (2015), jadi mungkin perlu sedikit pengeditan untuk versi sebelumnya.
sumber
sumber
Math.Ceiling
atau sesuatu.Inilah jawaban singkat yang menentukan unit secara otomatis.
"B" adalah untuk bit, "B" adalah untuk Byte dan "KMGTPEZY" masing-masing untuk kilo, mega, giga, tera, peta, exa, zetta dan yotta
Seseorang dapat mengembangkannya untuk memperhitungkan ISO / IEC80000 :
sumber
o
setelah KMGTPE: Its french (byte
adalahoctet
di Perancis). Untuk bahasa lain hanya gantio
denganb
sumber
Jika Anda mencoba mencocokkan ukuran seperti yang ditunjukkan pada tampilan detail Windows Explorer, ini adalah kode yang Anda inginkan:
Ini tidak hanya cocok dengan Explorer tetapi juga akan memberikan string yang diterjemahkan untuk Anda dan cocok dengan perbedaan dalam versi Windows (misalnya di Win10, K = 1000 vs versi sebelumnya K = 1024).
sumber
Campuran semua solusi :-)
sumber
Ada satu proyek open source yang bisa melakukan itu dan banyak lagi.
http://humanizr.net/#bytesize
https://github.com/MehdiK/Humanizer
sumber
Seperti solusi @ NET3. Gunakan shift alih-alih divisi untuk menguji kisaran
bytes
, karena pembagian membutuhkan biaya CPU lebih banyak.sumber
Saya menganggap Anda sedang mencari "1,4 MB" bukannya "1468006 byte"?
Saya tidak berpikir ada cara built-in untuk melakukan itu di .NET. Anda harus mencari tahu unit mana yang sesuai, dan memformatnya.
Sunting: Berikut beberapa contoh kode untuk melakukan hal itu:
http://www.codeproject.com/KB/cpp/formatsize.aspx
sumber
Bagaimana dengan beberapa rekursi:
Maka Anda menyebutnya:
sumber
2 sen saya:
string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
sumber
Satu lagi pendekatan, untuk apa nilainya. Saya menyukai solusi teroptimalkan @humbads yang dirujuk di atas, jadi telah menyalin prinsipnya, tetapi saya telah menerapkannya sedikit berbeda.
Saya kira itu masih bisa diperdebatkan, apakah itu harus menjadi metode ekstensi (karena tidak semua lama harus ukuran byte), tapi saya suka mereka, dan di suatu tempat saya dapat menemukan metode ketika saya membutuhkannya nanti!
Mengenai unit, saya tidak berpikir saya pernah mengatakan 'Kibibyte' atau 'Mebibyte' dalam hidup saya, dan sementara saya skeptis dengan standar yang ditegakkan daripada berkembang, saya kira itu akan menghindari kebingungan dalam jangka panjang .
sumber
Saya menggunakan metode ekstensi Panjang di bawah ini untuk mengonversi string ukuran yang dapat dibaca manusia. Metode ini adalah implementasi C # dari solusi Java untuk pertanyaan yang sama yang diposting di Stack Overflow, di sini .
sumber