Это не самый эффективный способ сделать это, но его легче читать, если вы не знакомы с математикой журнала, и он должен быть достаточно быстрым для большинства сценариев.
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]);
Я полагаю, что вы могли бы использовать Math.Log для определения порядка вместо использования цикла while.
Франсуа Бота
12
Кроме того, КБ составляет 1000 байтов. 1024 байта - это КиБ .
Константин
13
@ Константин ну что зависит от ОС? Windows по-прежнему считает 1024 байта как 1 КБ и 1 МБ = 1024 КБ. Лично я хочу выбросить KiB из окна и просто считать каждую вещь, используя 1024? ...
Питер
4
@Petoj это не зависит от ОС, определение не зависит от ОС. Материал из Википедии: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
Я предпочитаю этот код, так как он работает быстрее, но я немного изменил его, чтобы учесть различное количество десятичных знаков. Меньшие числа лучше отображать с двумя десятичными разрядами, например, 1,38 МБ, тогда как для больших чисел требуется меньше десятичных разрядов, например, 246 КБ или 23,5 КБ:
Myke Black
321
используя журнал для решения проблемы ....
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];}
Также в C #, но должно быть легко конвертировать. Также я округлил до 1 десятичного знака для удобства чтения.
В основном определите количество десятичных знаков в базе 1024, а затем разделите на 1024 ^ десятичных знаков.
И некоторые примеры использования и вывода:
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
Изменить: было указано, что я пропустил math.floor, поэтому я включил его. (Convert.ToInt32 использует округление, а не усечение, и поэтому необходим Floor.) Спасибо за улов.
Edit2: было несколько комментариев об отрицательных размерах и 0 байтных размерах, поэтому я обновил, чтобы обработать эти 2 случая.
Я хочу предупредить, что хотя этот ответ действительно является небольшим фрагментом кода, он не самый оптимизированный. Я бы хотел, чтобы вы взглянули на метод, опубликованный @humbads. Я провел микротестирование, отправив 10 000 000 случайно сгенерированных файловых форматов обоими методами, и это приводит к выводу, что его метод работает на ~ 30% быстрее. Однако я провел дальнейшую очистку его метода (ненужные задания и кастинг). Кроме того, я запустил тест с отрицательным размером (когда вы сравниваете файлы), в то время как метод хумбада безошибочно обрабатывает этот метод Log, и он выдаст исключение!
IvanL
1
Да, вы должны добавить Math.Abs для отрицательных размеров. Кроме того, код не обрабатывает случай, если размер точно равен 0.
dasheddot
Math.Abs, Math.Floor, Math.Log, Преобразование в целое число, Math.Round, Math.Pow, Math.Sign, Добавление, Умножение, Деление? Разве эта тонна математики не сделала огромный скачок на процессоре. Это, вероятно, медленнее, чем код @humbads
Джейсон Рагаса
Сбой double.MaxValue(место = 102)
BrunoLM
Прекрасно работает! Чтобы имитировать работу окон (по крайней мере на моем Windows 7 Ultimate), замените Math.Round на Math.Ceiling. Еще раз спасибо. Мне нравится это решение.
H_He
101
Тестовая и значительно оптимизированная версия запрашиваемой функции размещена здесь:
+1! Проще и проще! Заставляет процессор выполнять математику легко и быстро!
Джейсон Рагаса
К вашему сведению, вы нигде не используете это значение, double readable = (i < 0 ? -i : i);поэтому удалите его. еще один актерский состав - редунат
Ройи Намир,
Я удалил актерский состав, добавил комментарии и исправил проблему со знаком минус.
хамбадс
Отличный ответ. Спасибо, почему бы просто не использовать Math.Abs?
kspearrin
1
(i <0? -i: i) примерно на 15% быстрее, чем Math.Abs. Для одного миллиона вызовов Math.Abs на моей машине медленнее на 0,5 миллисекунды - 3,2 мс против 3,7 мс.
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();}
Я мог бы быть нубом, но использование такой гигантской пушки, как pinvoke для убийства этой утки, является большим злоупотреблением.
Барт
27
Это то, что использует проводник? Если это так, то он очень полезен для того, чтобы позволить людям соответствовать размеру файла, который вы им показываете, и тому, что показывает проводник.
Эндрю Бакер
8
И тот, который не изобретает велосипед
Мэтью Локк
Разве 11 символов не являются постоянным лимитом и немного низкими для этого? Я имею в виду, что другие языки могут использовать больше символов для сокращения размера в байтах или других стилей форматирования.
Рэй
1
@ Но новичкам нужно некоторое время, чтобы научиться мудрости в этом: «Мы должны забыть о малой эффективности, скажем, в 97% случаев: преждевременная оптимизация - корень всего зла» ubiquity.acm.org/article.cfm? id = 1513451
Мэтью Локк
22
Еще один способ обработать его, без каких-либо циклов и с поддержкой отрицательного размера (имеет смысл для таких вещей, как дельта размера файла):
Хороший ответ. Должна быть проблема, когда размер файла слишком мал, и в этом случае / 1024 возвращает 0. Вы можете использовать дробный тип и вызов Math.Ceilingили что-то еще.
Nawfal
10
Вот краткий ответ, который определяет единицу автоматически.
для всех интересно , почему есть oпосле того, как KMGTPE: Его французский ( byteэто octetна французском языке). Для любого другого языка просто заменить oсb
Вы должны проверить: while (size> = 1024 && s <suffixes.Length).
TcKs
Нет ... 64-разрядное целое число со знаком не может выходить за пределы ZB ..., которое представляет числа 2 ^ 70.
bobwienholt
7
Так зачем ставить в YB?
Конфигуратор
Мне самому этот ответ нравится больше всего, но все здесь действительно вкладывают действительно неэффективные решения, вы должны использовать "size = size >> 10", смещение намного быстрее, чем деление ... и я думаю, что хорошо иметь здесь есть дополнительный греческий спецификатор, потому что в ближайшем будущем положительной функции DLR не потребуется «длинный размер». Вы можете использовать 128-битный векторный процессор или что-то, что может содержать ZB и больше;)
RandomNickName42
4
Bitshifting был более эффективным, чем деление во времена кодирования C на металле. Вы провели тестирование на .NET, чтобы увидеть, действительно ли бит-смещение более эффективно? Не так давно я посмотрел на состояние xor-swap и обнаружил, что он на самом деле медленнее в .NET по сравнению с использованием временной переменной.
Пит
7
Если вы пытаетесь соответствовать размеру, как показано в подробном представлении Windows Explorer, вам нужен следующий код:
Это будет не только точно соответствовать Explorer, но также предоставит переведенные для вас строки и совпадет с различиями в версиях Windows (например, в Win10, K = 1000 против предыдущих версий K = 1024).
Этот код не компилируется, вам нужно указать dll, из которой пришла функция. Таким образом, весь прототип функции звучит так: [DllImport ("shlwapi.dll", CharSet = CharSet.Auto, SetLastError = true)] общедоступный статический extern long StrFormatKBSize (long qdw, [MarshalAs (UnmanagedType.LPTStr)] StringBuilder int cszBuf, ); Позвольте мне быть первым, кто поддержит это решение. Зачем изобретать велосипед, если колесо уже изобретено? Это типичный подход всех программистов на C #, но, к сожалению, C # не достигает всех целей, которых достигает C ++.
TarmoPikaro
И еще одно исправление: Int64.MaxValue достигает 9,223,372,036,854,775,807, что требует выделения размера буфера 25+ - на всякий случай я округлил его до 32 (а не 11, как в демонстрационном коде выше).
TarmoPikaro
Спасибо @TarmoPikaro. Когда я скопировал из моего рабочего кода, я пропустил DllImport. Также увеличен размер буфера по вашей рекомендации. Хороший улов!
Metalogic
Впечатляющий подход
tbhaxor
Это показывает только единицу КБ. Идея состоит в том, чтобы показать самую большую единицу в зависимости от стоимости.
jstuardo
5
Смесь всех решений :-)
/// <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
}
Как и решение @ NET3. Используйте сдвиг вместо деления для проверки диапазона bytes, потому что деление требует больше ресурсов процессора.
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]);}
Поскольку эти функции предназначены для презентаций, необходимо предоставить культуру, например: string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
В зависимости от контекста килобайт может быть либо 1000, либо 1024 байта . То же самое касается МБ, ГБ и т. Д.
Килобайт означает 1000 байтов ( wolframalpha.com/input/?i=kilobyte ), это не зависит от контекста. Как говорит Википедия, он исторически зависел от контекста, и де-юре он был изменен в 1998 году, а изменения де-факто начались примерно в 2005 году, когда терабайтные жесткие диски привлекли его внимание общественности. Термин для 1024 байтов - это кибибайт. Код, который переключает их в зависимости от культуры, производит неверную информацию.
Супербест
1
Еще один подход, для чего это стоит. Мне понравилось оптимизированное решение @humbads, упомянутое выше, поэтому я скопировал этот принцип, но я реализовал его немного по-другому.
Я предполагаю, что это спорный вопрос о том, должен ли это быть метод расширения (поскольку не все длинные значения обязательно имеют размер в байтах), но они мне нравятся, и где-то я могу найти метод, когда он мне понадобится в следующий раз!
Что касается юнитов, я не думаю, что когда-либо говорил «Kibibyte» или «Mebibyte» в своей жизни, и, хотя я скептически отношусь к таким неукоснительным, а не к развитым стандартам, я полагаю, что в долгосрочной перспективе это позволит избежать путаницы ,
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);}}
Я использую метод длинного расширения, приведенный ниже, чтобы преобразовать его в удобочитаемую строку размера. Этот метод является реализацией C # решения Java этого же вопроса, опубликованного в Stack Overflow, здесь .
/// <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";}
Ответы:
Это не самый эффективный способ сделать это, но его легче читать, если вы не знакомы с математикой журнала, и он должен быть достаточно быстрым для большинства сценариев.
источник
The unit was established by the International Electrotechnical Commission (IEC) in 1998 and has been accepted for use by all major standards organizations
используя журнал для решения проблемы ....
Также в C #, но должно быть легко конвертировать. Также я округлил до 1 десятичного знака для удобства чтения.
В основном определите количество десятичных знаков в базе 1024, а затем разделите на 1024 ^ десятичных знаков.
И некоторые примеры использования и вывода:
Изменить: было указано, что я пропустил math.floor, поэтому я включил его. (Convert.ToInt32 использует округление, а не усечение, и поэтому необходим Floor.) Спасибо за улов.
Edit2: было несколько комментариев об отрицательных размерах и 0 байтных размерах, поэтому я обновил, чтобы обработать эти 2 случая.
источник
double.MaxValue
(место = 102)Тестовая и значительно оптимизированная версия запрашиваемой функции размещена здесь:
C # Удобочитаемый размер файла - оптимизированная функция
Исходный код:
источник
double readable = (i < 0 ? -i : i);
поэтому удалите его. еще один актерский состав - редунатMath.Abs
?От: http://www.pinvoke.net/default.aspx/shlwapi/StrFormatByteSize.html
источник
Еще один способ обработать его, без каких-либо циклов и с поддержкой отрицательного размера (имеет смысл для таких вещей, как дельта размера файла):
А вот и тестовый набор:
источник
Оформить заказ на библиотеку ByteSize . Это
System.TimeSpan
для байтов!Он обрабатывает преобразование и форматирование для вас.
Это также делает строковое представление и анализ.
источник
Мне нравится использовать следующий метод (он поддерживает до терабайтов, что достаточно для большинства случаев, но его легко расширить):
Помните, что это написано для C # 6.0 (2015), поэтому для более ранних версий может потребоваться небольшое редактирование.
источник
источник
Math.Ceiling
или что-то еще.Вот краткий ответ, который определяет единицу автоматически.
«b» для бита, «B» для байта и «KMGTPEZY» соответственно для кило, мега, гига, тера, пета, exa, zetta и yotta
Можно расширить его, чтобы принять во внимание ISO / IEC80000 :
источник
o
после того, как KMGTPE: Его французский (byte
этоoctet
на французском языке). Для любого другого языка просто заменитьo
сb
источник
Если вы пытаетесь соответствовать размеру, как показано в подробном представлении Windows Explorer, вам нужен следующий код:
Это будет не только точно соответствовать Explorer, но также предоставит переведенные для вас строки и совпадет с различиями в версиях Windows (например, в Win10, K = 1000 против предыдущих версий K = 1024).
источник
Смесь всех решений :-)
источник
Есть один проект с открытым исходным кодом, который может сделать это и многое другое.
http://humanizr.net/#bytesize
https://github.com/MehdiK/Humanizer
источник
Как и решение @ NET3. Используйте сдвиг вместо деления для проверки диапазона
bytes
, потому что деление требует больше ресурсов процессора.источник
Я полагаю, вы ищете "1,4 МБ" вместо "1468006 байт"?
Я не думаю, что есть встроенный способ сделать это в .NET. Вам нужно просто выяснить, какой блок подходит, и отформатировать его.
Изменить: Вот пример кода, чтобы сделать это:
http://www.codeproject.com/KB/cpp/formatsize.aspx
источник
Как насчет рекурсии:
Тогда вы называете это:
источник
Мои 2 цента:
string.Format(CultureInfo.CurrentCulture, "{0:0.##} {1}", fileSize, unit);
источник
Еще один подход, для чего это стоит. Мне понравилось оптимизированное решение @humbads, упомянутое выше, поэтому я скопировал этот принцип, но я реализовал его немного по-другому.
Я предполагаю, что это спорный вопрос о том, должен ли это быть метод расширения (поскольку не все длинные значения обязательно имеют размер в байтах), но они мне нравятся, и где-то я могу найти метод, когда он мне понадобится в следующий раз!
Что касается юнитов, я не думаю, что когда-либо говорил «Kibibyte» или «Mebibyte» в своей жизни, и, хотя я скептически отношусь к таким неукоснительным, а не к развитым стандартам, я полагаю, что в долгосрочной перспективе это позволит избежать путаницы ,
источник
Я использую метод длинного расширения, приведенный ниже, чтобы преобразовать его в удобочитаемую строку размера. Этот метод является реализацией C # решения Java этого же вопроса, опубликованного в Stack Overflow, здесь .
источник