Как преобразовать размер байта в человекочитаемый формат в Java?

Как преобразовать размер байта в человекочитаемый формат в Java? Например, 1024 должно стать «1 Кб», а 1024 * 1024 должно стать «1 Мб».

Мне надоело писать этот метод для каждого проекта. Есть ли в Apache Commons статические методы для этого?

 Aaron Digulla21 сент. 2010 г., 11:52
 Pascal Cuoq21 сент. 2010 г., 10:48
Если вы используете стандартные единицы измерения, 1024 должно стать «1 КБ», а 1024 * 1024 - «1 МБ».en.wikipedia.org/wiki/Binary_prefix
 Christian Esken15 июл. 2016 г., 15:28
@DerMike Вы упомянули, что "Пока такая библиотека не существует". Теперь это стало правдой. :-)stackoverflow.com/questions/3758606/...
 Aaron Digulla21 сент. 2010 г., 10:49
@Pascal: должно быть несколько функций или опция для указания базы и единицы измерения.
 JeremyP21 сент. 2010 г., 12:48
@Pascal Cuoq: Спасибо за ссылку. Я не осознавал, пока не прочитал, что здесь, в ЕС, мы обязаны использовать правильные префиксы по закону.

Ответы на вопрос(22)

public String humanReadable(long size) {
    long limit = 10 * 1024;
    long limit2 = limit * 2 - 1;
    String negative = "";
    if(size < 0) {
        negative = "-";
        size = Math.abs(size);
    }

    if(size < limit) {
        return String.format("%s%s bytes", negative, size);
    } else {
        size = Math.round((double) size / 1024);
        if (size < limit2) {
            return String.format("%s%s kB", negative, size);
        } else {
            size = Math.round((double)size / 1024);
            if (size < limit2) {
                return String.format("%s%s MB", negative, size);
            } else {
                size = Math.round((double)size / 1024);
                if (size < limit2) {
                    return String.format("%s%s GB", negative, size);
                } else {
                    size = Math.round((double)size / 1024);
                        return String.format("%s%s TB", negative, size);
                }
            }
        }
    }
}

ответ aioobe.

Изменения:

Locale параметр, потому что некоторые языки используют. и другие, как десятичная точка.читабельный код
private static final String[] SI_UNITS = { "B", "kB", "MB", "GB", "TB", "PB", "EB" };
private static final String[] BINARY_UNITS = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };

public static String humanReadableByteCount(final long bytes, final boolean useSIUnits, final Locale locale)
{
    final String[] units = useSIUnits ? SI_UNITS : BINARY_UNITS;
    final int base = useSIUnits ? 1000 : 1024;

    // When using the smallest unit no decimal point is needed, because it's the exact number.
    if (bytes < base) {
        return bytes + " " + units[0];
    }

    final int exponent = (int) (Math.log(bytes) / Math.log(base));
    final String unit = units[exponent];
    return String.format(locale, "%.1f %s", bytes / Math.pow(base, exponent), unit);
}
    public static String floatForm (double d)
    {
       return new DecimalFormat("#.##").format(d);
    }


    public static String bytesToHuman (long size)
    {
        long Kb = 1  * 1024;
        long Mb = Kb * 1024;
        long Gb = Mb * 1024;
        long Tb = Gb * 1024;
        long Pb = Tb * 1024;
        long Eb = Pb * 1024;

        if (size <  Kb)                 return floatForm(        size     ) + " byte";
        if (size >= Kb && size < Mb)    return floatForm((double)size / Kb) + " Kb";
        if (size >= Mb && size < Gb)    return floatForm((double)size / Mb) + " Mb";
        if (size >= Gb && size < Tb)    return floatForm((double)size / Gb) + " Gb";
        if (size >= Tb && size < Pb)    return floatForm((double)size / Tb) + " Tb";
        if (size >= Pb && size < Eb)    return floatForm((double)size / Pb) + " Pb";
        if (size >= Eb)                 return floatForm((double)size / Eb) + " Eb";

        return "???";
    }

Formatter.formatFileSize () .

Альтернативно, вот решение, основанное наэтот популярный пост :

  /**
   * formats the bytes to a human readable format
   *
   * @param si true if each kilo==1000, false if kilo==1024
   */
  @SuppressLint("DefaultLocale")
  public static String humanReadableByteCount(final long bytes,final boolean si)
    {
    final int unit=si ? 1000 : 1024;
    if(bytes<unit)
      return bytes+" B";
    double result=bytes;
    final String unitsToUse=(si ? "k" : "K")+"MGTPE";
    int i=0;
    final int unitsCount=unitsToUse.length();
    while(true)
      {
      result/=unit;
      if(result<unit)
        break;
      // check if we can go further:
      if(i==unitsCount-1)
        break;
      ++i;
      }
    final StringBuilder sb=new StringBuilder(9);
    sb.append(String.format("%.1f ",result));
    sb.append(unitsToUse.charAt(i));
    if(si)
      sb.append('B');
    else sb.append('i').append('B');
    final String resultStr=sb.toString();
    return resultStr;
    }
 android developer05 мая 2014 г., 15:39
@aioobe Правильно, это из-за предположения (что правильно), что я обрабатываю «длинный» тип переменной. Кроме того, это основано на предположении, что единицы будут по крайней мере тем, что я написал. Если вы используете меньше единиц, это приведет к странным результатам (предпочтительнее, чем значения меньше 1, а не значения больше 1000).
 aioobe06 мая 2014 г., 10:00
Да, но в нынешнем виде этосерьезно ущербный.
 android developer05 мая 2014 г., 14:30
@aioobe, но это означает, что цикл может остановиться, когда i == unitsCount, что означает i == 6, что означает, что «charAt» завершится ошибкой ...
 android developer05 авг. 2014 г., 01:10
@aioobe Я также добавил короткий способ сделать это в случае, если вы используете Android.
 aioobe05 мая 2014 г., 14:02
Похоже, у вас в цикле for произошла ошибка. Я думаю, что это должно бытьunitsCount и неunitsCount-1.
 android developer06 мая 2014 г., 13:52
@aioobe Может быть, использование этого может помочь:stackoverflow.com/questions/1305827/... ?
 android developer06 мая 2014 г., 13:50
@aioobe Правильно. Я починю это. Кстати, ваш алгоритм также может дать странный результат. попробуйте указать в качестве аргумента "999999, true". он покажет «1000,0 кБ», поэтому он округлен, но когда люди видят его, они могут задаться вопросом: почему он не может показать 1 МБ, так как 1000 КБ = 1 МБ ... Как вы думаете, как это должно быть обработано? Это из-за String.format, но я не уверен, как это должно быть исправлено.
 aioobe05 мая 2014 г., 14:54
if(result<unit) break; пойдет до этого. Не волнуйтесь. (Если вы проверите его, вы заметите, что можете полностью пропустить условие цикла for.)

чтобы получить точную информацию, созданную на основеATM_CashWithdrawl концепция.

getFullMemoryUnit(): Total: [123 MB], Max: [1 GB, 773 MB, 512 KB], Free: [120 MB, 409 KB, 304 Bytes]
public static String getFullMemoryUnit(long unit) {
    long BYTE = 1024, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long KILO_BYTE, MEGA_BYTE = 0, GIGA_BYTE = 0, TERA_BYTE = 0;
    unit = Math.abs(unit);
    StringBuffer buffer = new StringBuffer();
    if ( unit / TB > 0 ) {
        TERA_BYTE = (int) (unit / TB);
        buffer.append(TERA_BYTE+" TB");
        unit -= TERA_BYTE * TB;
    }
    if ( unit / GB > 0 ) {
        GIGA_BYTE = (int) (unit / GB);
        if (TERA_BYTE != 0) buffer.append(", ");
        buffer.append(GIGA_BYTE+" GB");
        unit %= GB;
    }
    if ( unit / MB > 0 ) {
        MEGA_BYTE = (int) (unit / MB);
        if (GIGA_BYTE != 0) buffer.append(", ");
        buffer.append(MEGA_BYTE+" MB");
        unit %= MB;
    }
    if ( unit / KB > 0 ) {
        KILO_BYTE = (int) (unit / KB);
        if (MEGA_BYTE != 0) buffer.append(", ");
        buffer.append(KILO_BYTE+" KB");
        unit %= KB;
    }
    if ( unit > 0 ) buffer.append(", "+unit+" Bytes");
    return buffer.toString();
}

Я только что изменил кодfacebookarchive-StringUtils чтобы получить формат ниже. Тот же формат, который вы получите при использованииapache.hadoop-StringUtils

getMemoryUnit(): Total: [123.0 MB], Max: [1.8 GB], Free: [120.4 MB]
public static String getMemoryUnit(long bytes) {
    DecimalFormat oneDecimal = new DecimalFormat("0.0");
    float BYTE = 1024.0f, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
    long absNumber = Math.abs(bytes);
    double result = bytes;
    String suffix = " Bytes";
    if (absNumber < MB) {
        result = bytes / KB;
        suffix = " KB";
    } else if (absNumber < GB) {
        result = bytes / MB;
        suffix = " MB";
    } else if (absNumber < TB) {
        result = bytes / GB;
        suffix = " GB";
    }
    return oneDecimal.format(result) + suffix;
}

Пример использования вышеперечисленных методов:

public static void main(String[] args) {
    Runtime runtime = Runtime.getRuntime();
    int availableProcessors = runtime.availableProcessors();

    long heapSize = Runtime.getRuntime().totalMemory(); 
    long heapMaxSize = Runtime.getRuntime().maxMemory();
    long heapFreeSize = Runtime.getRuntime().freeMemory();

    System.out.format("Total: [%s], Max: [%s], Free: [%s]\n", heapSize, heapMaxSize, heapFreeSize);
    System.out.format("getMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getMemoryUnit(heapSize), getMemoryUnit(heapMaxSize), getMemoryUnit(heapFreeSize));
    System.out.format("getFullMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
            getFullMemoryUnit(heapSize), getFullMemoryUnit(heapMaxSize), getFullMemoryUnit(heapFreeSize));
}

Байты, чтобы получить выше формат

Total: [128974848], Max: [1884815360], Free: [126248240]

Для отображения времени в удобочитаемом формате используйте эту функциюmillisToShortDHMS(long duration).

String[] fileSizeUnits = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
public String calculateProperFileSize(double bytes){
    String sizeToReturn = "";
    int index = 0;
    for(index = 0; index < fileSizeUnits.length; index++){
        if(bytes < 1024){
            break;
        }
        bytes = bytes / 1024;
    }

и вы увидите размер единицы до этой единицы (если у вашего файла такая большая длина) System.out.println ("Размер файла в правильном формате:" + bytes + "" + fileSizeUnits [индекс]); sizeToReturn = String.valueOf (bytes) + "" + fileSizeUnits [index]; return sizeToReturn; }

JSR 363? Его модули расширения модуля, такие как Unicode CLDR (вGitHub: uom-системы) сделать все это для вас.

Ты можешь использоватьMetricPrefix включается в каждую реализацию илиBinaryPrefix (сопоставимо с некоторыми из приведенных выше примеров), и если вы, например, жить и работать в Индии или соседней стране,IndianPrefix (также в общем модуле uom-systems) позволяет также использовать и форматировать "Crore Bytes" или "Lakh Bytes".

  private String bytesIntoHumanReadable(long bytes) {
        long kilobyte = 1024;
        long megabyte = kilobyte * 1024;
        long gigabyte = megabyte * 1024;
        long terabyte = gigabyte * 1024;

        if ((bytes >= 0) && (bytes < kilobyte)) {
            return bytes + " B";

        } else if ((bytes >= kilobyte) && (bytes < megabyte)) {
            return (bytes / kilobyte) + " KB";

        } else if ((bytes >= megabyte) && (bytes < gigabyte)) {
            return (bytes / megabyte) + " MB";

        } else if ((bytes >= gigabyte) && (bytes < terabyte)) {
            return (bytes / gigabyte) + " GB";

        } else if (bytes >= terabyte) {
            return (bytes / terabyte) + " TB";

        } else {
            return bytes + " Bytes";
        }
    }
 Joshua Pinter27 февр. 2018 г., 18:33
Мне это нравится, потому что за ним легко следовать и легко понять.

Формат файла размером в МБ, ГБ и т. Д.

Пока нет готового ответа, я могу жить с решением:

private static final long K = 1024;
private static final long M = K * K;
private static final long G = M * K;
private static final long T = G * K;

public static String convertToStringRepresentation(final long value){
    final long[] dividers = new long[] { T, G, M, K, 1 };
    final String[] units = new String[] { "TB", "GB", "MB", "KB", "B" };
    if(value < 1)
        throw new IllegalArgumentException("Invalid file size: " + value);
    String result = null;
    for(int i = 0; i < dividers.length; i++){
        final long divider = dividers[i];
        if(value >= divider){
            result = format(value, divider, units[i]);
            break;
        }
    }
    return result;
}

private static String format(final long value,
    final long divider,
    final String unit){
    final double result =
        divider > 1 ? (double) value / (double) divider : (double) value;
    return new DecimalFormat("#,##0.#").format(result) + " " + unit;
}

Тестовый код:

public static void main(final String[] args){
    final long[] l = new long[] { 1l, 4343l, 43434334l, 3563543743l };
    for(final long ll : l){
        System.out.println(convertToStringRepresentation(ll));
    }
}

Вывод (на моем немецком языке):

1 B
4,2 KB
41,4 MB
3,3 GB

Изменить: я открылПроблема с запросом этой функции для Google Guava, Возможно, кто-то захочет поддержать это.

 tom24 окт. 2013 г., 14:30
Если вы измените последнюю строку, чтобы вернуть NumberFormat.getFormat ("#, ## 0. #"). Format (result) + "" + unit; это работает и в GWT! Спасибо за это, это все еще не в Гуаве.
 aioobe21 сент. 2010 г., 11:29
Почему 0 неверный размер файла?
 Sean Patrick Floyd21 сент. 2010 г., 11:38
@aioobe это было в моем случае использования (отображение размера загруженного файла), но, возможно, это не универсально

Math.pow() а такжеMath.log() методы без ущерба для простоты, поскольку коэффициент между единицами (например, B, KB, MB и т. д.) равен 1024, что составляет 2 ^ 10.Long у класса есть удобныйnumberOfLeadingZeros() метод, который мы можем использовать, чтобы определить, в какую единицу входит значение размера.

Ключевой момент: Единицы измерения имеют расстояние в 10 бит (1024 = 2 ^ 10), что означает позицию старшего 1 бита, или, другими словами,число ведущих нулей - различаются на 10 (байт = КБ * 1024, КБ = МБ * 1024 и т. д.).

Корреляция между числом ведущих нулей и единицей измерения:

# of leading 0's   Size unit
-------------------------------
>53                B (Bytes)
>43                KB
>33                MB
>23                GB
>13                TB
>3                 PB
<=2                EB

Финальный код:

public static String formatSize(long v) {
    if (v < 1024) return v + " B";
    int z = (63 - Long.numberOfLeadingZeros(v)) / 10;
    return String.format("%.1f %sB", (double)v / (1L << (z*10)), " KMGTPE".charAt(z));
}

которая содержит форматирование модулей. Я добавил это кtriava библиотека, как единственная другая существующая библиотека, кажется, для Android.

Он может форматировать числа с произвольной точностью в 3 различных системах (SI, IEC, JEDEC) и различных вариантах вывода. Вот несколько примеров кода измодульные тесты triava:

UnitFormatter.formatAsUnit(1126, UnitSystem.SI, "B");
// = "1.13kB"
UnitFormatter.formatAsUnit(2094, UnitSystem.IEC, "B");
// = "2.04KiB"

Печать точных килограмм, мегаполисов (здесь с W = Watt):

UnitFormatter.formatAsUnits(12_000_678, UnitSystem.SI, "W", ", ");
// = "12MW, 678W"

Вы можете передать DecimalFormat, чтобы настроить вывод:

UnitFormatter.formatAsUnit(2085, UnitSystem.IEC, "B", new DecimalFormat("0.0000"));
// = "2.0361KiB"

Для произвольных операций с килограммами или мега значениями вы можете разделить их на компоненты:

UnitComponent uc = new  UnitComponent(123_345_567_789L, UnitSystem.SI);
int kilos = uc.kilo(); // 567
int gigas = uc.giga(); // 123

private static final String[] Q = new String[]{"", "K", "M", "G", "T", "P", "E"};

public String getAsString(long bytes)
{
    for (int i = 6; i > 0; i--)
    {
        double step = Math.pow(1024, i);
        if (bytes > step) return String.format("%3.1f %s", bytes / step, Q[i]);
    }
    return Long.toString(bytes);
}

        long Kb = 1024;
        long Mb = Kb * 1024;
        long Gb = Mb * 1024;
        long Tb = Gb * 1024;
        long Pb = Tb * 1024;
        long Eb = Pb * 1024;

        if (size < Kb) return size.ToString() + " byte";
        if (size < Mb) return (size / Kb).ToString("###.##") + " Kb.";
        if (size < Gb) return (size / Mb).ToString("###.##") + " Mb.";
        if (size < Tb) return (size / Gb).ToString("###.##") + " Gb.";
        if (size < Pb) return (size / Tb).ToString("###.##") + " Tb.";
        if (size < Eb) return (size / Pb).ToString("###.##") + " Pb.";
        if (size >= Eb) return (size / Eb).ToString("###.##") + " Eb.";

        return "invalid size";

Байтовые единицы позволяет сделать это так:

long input2 = 1024 * 1024;

Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2));

Assert.assertEquals("1.024 KB", DecimalByteUnit.format(input1, "#.0"));
Assert.assertEquals("1.049 MB", DecimalByteUnit.format(input2, "#.000"));

NumberFormat format = new DecimalFormat("#.#");
Assert.assertEquals("1 KiB", BinaryByteUnit.format(input1, format));
Assert.assertEquals("1 MiB", BinaryByteUnit.format(input2, format));

Я написал другую библиотеку под названиемхранения-единицы это позволяет вам сделать это так:

String formattedUnit1 = StorageUnits.formatAsCommonUnit(input1, "#");
String formattedUnit2 = StorageUnits.formatAsCommonUnit(input2, "#");
String formattedUnit3 = StorageUnits.formatAsBinaryUnit(input1);
String formattedUnit4 = StorageUnits.formatAsBinaryUnit(input2);
String formattedUnit5 = StorageUnits.formatAsDecimalUnit(input1, "#.00", Locale.GERMAN);
String formattedUnit6 = StorageUnits.formatAsDecimalUnit(input2, "#.00", Locale.GERMAN);
String formattedUnit7 = StorageUnits.formatAsBinaryUnit(input1, format);
String formattedUnit8 = StorageUnits.formatAsBinaryUnit(input2, format);

Assert.assertEquals("1 kB", formattedUnit1);
Assert.assertEquals("1 MB", formattedUnit2);
Assert.assertEquals("1.00 KiB", formattedUnit3);
Assert.assertEquals("1.00 MiB", formattedUnit4);
Assert.assertEquals("1,02 kB", formattedUnit5);
Assert.assertEquals("1,05 MB", formattedUnit6);
Assert.assertEquals("1 KiB", formattedUnit7);
Assert.assertEquals("1 MiB", formattedUnit8);

Если вы хотите форсировать определенный юнит, сделайте это:

String formattedUnit9 = StorageUnits.formatAsKibibyte(input2);
String formattedUnit10 = StorageUnits.formatAsCommonMegabyte(input2);

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
 Sebastian Hoß17 авг. 2016 г., 22:03
Да, спасибо! Отредактировал себя, чтобы добавить пример длябайтовые единицы также
 Ed Cottrell17 авг. 2016 г., 20:28
Вы должны раскрыть свою принадлежность к этой библиотеке. Я отредактировал ваш пост, чтобы сделать это.

Используйте Android встроенный класс

Для Android есть классFormatter, Просто один код, и все готово.

android.text.format.Formatter.formatShortFileSize(activityContext, bytes);

Это какformatFileSize(), но пытается генерировать более короткие числа (показывая меньше десятичных знаков).

android.text.format.Formatter.formatFileSize(activityContext, bytes);

Форматирует размер контента в байтах, килобайтах, мегабайтах и ​​т. Д.

 AZ_18 окт. 2017 г., 13:50
но он возвращает тебе String, верно! Вы можете локализовать эту строку. Я думаю, это должно сработать, и тогда вы сможете распечатать локализованную строку или в операторе печати вы также можете указать локализацию.
 doraemon09 июн. 2016 г., 09:11
Как занять 4 знака после запятой? 2 десятичных знака не очень точны для моего ..
 shridutt kothari25 окт. 2015 г., 18:24
Должно быть лучшим ответом для ANDROID окончательно.
 Jared Burrows25 мая 2015 г., 05:50
Я ненавижу тот факт, что вы должны пройти вContext.
 zionpi29 мая 2015 г., 05:17
Откуда ты это знаешь?
 android developer17 окт. 2017 г., 11:33
@AZ_ Это не тот же класс. Это форматтер, который используется для formatShortFileSize:developer.android.com/reference/android/text/format/... , Как видите, функция там статическая.
 phreakhead14 мая 2016 г., 00:37
Вы передаете в контексте, так что он переводится в текущую локаль пользователя. В противном случае это была бы не очень полезная функция.
 android developer15 окт. 2017 г., 10:48
Можно ли заставить его использовать конкретную локаль? Просто когда используется арабский, я вижу арабские цифры (я использую его для себя, для тестирования / отладки)
 AZ_17 окт. 2017 г., 08:14
 dieter19 апр. 2015 г., 13:37
должен быть лучшим ответом для Android окончательно. Никаких дополнительных библиотек не требуется. +1
 HendraWD11 июн. 2018 г., 13:27
Я использовал принятый ответ, прежде чем я знаю это. Следует отметить, что в Build.VERSION_CODES.N и более ранних версиях вместо этого используются степени 1024, при этом KB = 1024 байта, MB = 1 048 576 байтов и т. Д. Что касается O, префиксы используются в их стандартных значениях в системе SI. , кБ = 1000 байт, МБ = 1 000 000 байт и т. д.

Ты можешь использоватьStringUtils«sTraditionalBinarPrefix:

public static String humanReadableInt(long number) {
    return TraditionalBinaryPrefix.long2String(number,””,1);
}

или, может быть, просто для развлечения, вот версия Go. Для простоты я включил только двоичный регистр вывода.

func sizeOf(bytes int64) string {
    const unit = 1024
    if bytes < unit {
        return fmt.Sprintf("%d B", bytes)
    }

    fb := float64(bytes)
    exp := int(math.Log(fb) / math.Log(unit))
    pre := "KMGTPE"[exp-1]
    div := math.Pow(unit, float64(exp))
    return fmt.Sprintf("%.1f %ciB", fb / div, pre)
}
 Rick-77704 окт. 2018 г., 17:23
Благодарим aioobe за алгоритм - см. Выше.
filename=filedilg.getSelectedFile().getAbsolutePath();
File file=new File(filename);

String disp=FileUtils.byteCountToDisplaySize(file.length());
System.out.println("THE FILE PATH IS "+file+"THIS File SIZE IS IN MB "+disp);

FileUtils.byteCountToDisplaySize(long size) будет работать, если ваш проект может зависеть отorg.apache.commons.io.

JavaDoc для этого метода

 Christian Esken05 янв. 2017 г., 14:39
@Tacroy Вы можете получить вывод октетов с помощью UnitFormatter в библиотеке triava. Вы можете передать любую единицу в байтах, ваттах или октетах. Пример, слегка модифицированный из примеров вgithub.com/trivago/triava: UnitFormatter.formatAsUnit (1126, UnitSystem.SI, "o"); // = "1.13 ko" Больше примеров в:stackoverflow.com/questions/3758606/...
 arunmoezhi24 июн. 2015 г., 21:02
Есть ли утилита для выполнения обратной операции. Получение байтов из числа читаемых человеком байтов?
 tksfz17 окт. 2017 г., 19:55
округляется до ближайшего гигабайта, когда> 1 гигабайт, а это означает, что точность, которую вы получаете из него, варьируется
 AZ_20 янв. 2015 г., 07:42
stackoverflow.com/a/26502430/185022 без какой-либо зависимости Android Native
 Tacroy17 дек. 2015 г., 16:26
К сожалению, эта функция не учитывает локали; например, на французском языке они всегда называют байты «октетами», поэтому, если вы собираетесь отобразить файл размером 100 КБ для французского пользователя, правильная метка будет 100 Ko.
 Iravanchi09 июл. 2012 г., 14:31
У меня уже есть commons-io в моем проекте, но в итоге я использовал код aioobe из-за поведения округления (см. Ссылку на JavaDoc)
Решение Вопроса

так и двоичных единиц):

public static String humanReadableByteCount(long bytes, boolean si) {
    int unit = si ? 1000 : 1024;
    if (bytes < unit) return bytes + " B";
    int exp = (int) (Math.log(bytes) / Math.log(unit));
    String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
    return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}

Пример вывода:

                              SI     BINARY

                   0:        0 B        0 B
                  27:       27 B       27 B
                 999:      999 B      999 B
                1000:     1.0 kB     1000 B
                1023:     1.0 kB     1023 B
                1024:     1.0 kB    1.0 KiB
                1728:     1.7 kB    1.7 KiB
              110592:   110.6 kB  108.0 KiB
             7077888:     7.1 MB    6.8 MiB
           452984832:   453.0 MB  432.0 MiB
         28991029248:    29.0 GB   27.0 GiB
       1855425871872:     1.9 TB    1.7 TiB
 9223372036854775807:     9.2 EB    8.0 EiB   (Long.MAX_VALUE)

Связанная статья:Java: форматирование размера байта в удобочитаемый формат

 aioobe21 июн. 2015 г., 20:25
@MohsinSyd, это символы "кило", "мега", "гига", "терра", "пета" и "exa".
 MohsinSyd07 мая 2015 г., 15:19
что такое kMGTPE?
 Wihan Fourie23 нояб. 2018 г., 06:52
Отличное решение, спасибо!
 Christian Strempfer16 нояб. 2015 г., 09:23
Код короткий, ноcharAt, ? оператор иString.format чтобы получить устройство не читается человеком ...
 kap19 апр. 2016 г., 14:35
Читатели узнают это. Лучше что-то, с чем они не знакомы и могут научиться этому, чем иметь что-то не так. При написании КБ пользователь, который знаком с ним, будет ожидать 1000, а незнакомый пользователь - 1024.
 Klitos Kyriacou21 дек. 2015 г., 13:35
@endolith Я думаю, что лучшей аналогией может быть определение калорий. Когда баночка диетического напитка говорит, что она содержит «Менее 1 калории», она использует разговорный и общепринятое определение «калории» - это действительно означает килокалорий. Но мы знаем, что это значит, поэтому это не большая проблема.
 Klitos Kyriacou21 дек. 2015 г., 11:34
Это выглядит очень подозрительно. Безопасно ли использовать арифметику с плавающей точкой, такую ​​как Math.log и Math.pow, а затем приводить к int? Эти методы не дают точного ответа, и вам повезло, что, например,(int) (Math.log(bytes) / Math.log(unit)) не дает один ответ меньше ожидаемого (на вашей конкретной машине).
 endolith21 дек. 2015 г., 13:17
@KlitosKyriacou "Но офицер, яне было превышение скорости! Отмой определение «километр», я собирался только 5 км / ч. "
 Samuel Harmer14 апр. 2017 г., 16:01
@KlitosKyriacou "Но мы знаем, что это значит, так что это не большая проблема" - я потерял счет, сколько раз я разговаривал с людьми, которые думают, что знают, какую единицу они имели в виду, но когда их спрашивают, у них нет разгадать и / или не согласиться с человеком, с которым, по их мнению, они согласны. Используйте единицы СИ для базы 10 и МЭК для базы 2, и мир станет лучше.
 duthen13 авг. 2015 г., 14:39
@Mazyod Для разработчиков iOS, вы можете использоватьNSByteCountFormatter, Например (по-быстрому):let bytes = 110592 NSByteCountFormatter.stringFromByteCount(Int64(bytes), countStyle: NSByteCountFormatterCountStyle.File) будет производить "111 КБ"
 Borys23 мая 2013 г., 15:33
Я думаю, что каждый должен отметить, что в вашем проекте заказчик хочет видеть значения в базе 2 (с разделением на 1024), но с общим префиксом. Не KiB, MiB, GiB и т. Д. Используйте KB, MB, GB, TB для этого.
 HendraWD11 июн. 2018 г., 13:08
Для разработчиков Android, вы можете использоватьstackoverflow.com/a/26502430/3940133 вместо
 Sean Patrick Floyd21 сент. 2010 г., 16:33
Единственное, что мне не нравится в этом, - то, что 1,0 КБ может быть отображено более красиво как 1 КБ. (Вот почему я использую DecimalFormat в своем ответе)
 endolith21 дек. 2015 г., 14:44
@KlitosKyriacou Но это 1000 калорий или 1024 калорий? Меры измеренияявляются предписывающий; иначе они бы не сработали. «Кило» означает «1000» в течение тысяч лет. Использовать его для ссылки на 1024 что-то не так.
 Klitos Kyriacou21 дек. 2015 г., 12:07
@endolith это пример прескриптивизма против дескриптивизма
 Klitos Kyriacou21 дек. 2015 г., 15:21
@endolith не отрицает, что это «неправильно» в соответствии со стандартом IEC. Тем не менее, его использование редко по сравнению с популярным использованием MB, чтобы означать 1024 * 1024 байта. «МБ» используется Windows, например. Использование MiB, хотя и правильное (согласно IEC), может сбить с толку читателей, незнакомых с ним. Все зависит от того, кто ваша аудитория. В любом случае, давайте не будем допускать, чтобы это отвлекало меня от моей основной критики, заключающейся в том, что этот метод может давать неверные результаты.
 endolith07 дек. 2015 г., 17:34
@Borys Использование «KB» для обозначения «1024 байта» неверно. Не делай этого.
 aioobe21 сент. 2010 г., 16:48
Я предпочитаю 1,0 КБ. Тогда ясно, сколько значимых цифр влечет за собой результат. (Это также, кажется, поведение, например,du команда в Linux.)

е. (есть еще один, который имеет более короткие коды)

    public static String BytesNumberToHumanReadableString(long bytes, bool SI1000orBinary1024)
    {

        int unit = SI1000orBinary1024 ? 1000 : 1024;
        if (bytes < unit) return bytes + " B";
        int exp = (int)(Math.Log(bytes) / Math.Log(unit));
        String pre = (SI1000orBinary1024 ? "kMGTPE" : "KMGTPE")[(exp - 1)] + (SI1000orBinary1024 ? "" : "i");
        return String.Format("{0:F1} {1}B", bytes / Math.Pow(unit, exp), pre);
    }

Технически говоря, если мы придерживаемся единиц СИ, эта процедура работает для любого регулярного использования чисел. Есть много других хороших ответов от экспертов. Предположим, вы выполняете привязку данных к числам в виде сетки, и стоит проверить из них подпрограммы, оптимизированные по производительности.

PS: опубликовано, потому что этот вопрос / ответ был на первом месте в поиске Google, пока я работаю над проектом C #.

Создать интерфейс:

public interface IUnits {
     public String format(long size, String pattern);
     public long getUnitSize();
}

Создать класс StorageUnits:

import java.text.DecimalFormat;

public class StorageUnits {
private static final long K = 1024;
private static final long M = K * K;
private static final long G = M * K;
private static final long T = G * K;

enum Unit implements IUnits {
    TERA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(), "TB", pattern);
        }
        @Override
        public long getUnitSize() {
            return T;
        }
        @Override
        public String toString() {
            return "Terabytes";
        }
    },
    GIGA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(), "GB", pattern);
        }
        @Override
        public long getUnitSize() {
            return G;
        }
        @Override
        public String toString() {
            return "Gigabytes";
        }
    },
    MEGA_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(), "MB", pattern);
        }
        @Override
        public long getUnitSize() {
            return M;
        }
        @Override
        public String toString() {
            return "Megabytes";
        }
    },
    KILO_BYTE {
        @Override
        public String format(long size, String pattern) {
            return format(size, getUnitSize(), "kB", pattern);
        }
        @Override
        public long getUnitSize() {
            return K;
        }
        @Override
        public String toString() {
            return "Kilobytes";
        }

    };
    String format(long size, long base, String unit, String pattern) {
        return new DecimalFormat(pattern).format(
                Long.valueOf(size).doubleValue() / Long.valueOf(base).doubleValue()
        ) + unit;
    }
}

public static String format(long size, String pattern) {
    for(Unit unit : Unit.values()) {
        if(size >= unit.getUnitSize()) {
            return unit.format(size, pattern);
        }
    }
    return ("???(" + size + ")???");
}

public static String format(long size) {
    return format(size, "#,##0.#");
}
}

Назови это:

class Main {
    public static void main(String... args) {
         System.out.println(StorageUnits.format(21885));
         System.out.println(StorageUnits.format(2188121545L));
    }
}

Выход:

21.4kB
2GB

Ваш ответ на вопрос