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

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

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

32 ответа

Решение

Вот мой пример (без циклов и обработок как единиц СИ, так и двоичных единиц):

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: Форматирование размера байта в удобочитаемый формат

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

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

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

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

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

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

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

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

Мы можем полностью избежать использования медленного 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));
}

Я недавно задавал тот же вопрос:

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

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

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. Возможно, кто-то захочет поддержать это.

  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";
        }
    }

Это модифицированная версия ответа 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);
}

Если вы используете Android, вы можете просто использовать 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;
    }

Kotlin Version через Extension Property

Если вы используете kotlin, довольно легко отформатировать размер файла с помощью следующих свойств расширения:


HumanizeUtils.kt

import java.io.File
import kotlin.math.log2
import kotlin.math.pow

/**
 * @author aminography
 */

val File.formatSize: String
    get() = length().formatAsFileSize

val Int.formatAsFileSize: String
    get() = toLong().formatAsFileSize

val Long.formatAsFileSize: String
    get() = log2(toDouble()).toInt().div(10).let {
        val precision = when (it) {
            0 -> 0; 1 -> 1; else -> 2
        }
        val prefix = arrayOf("", "K", "M", "G", "T", "P", "E", "Z", "Y")
        String.format("%.${precision}f ${prefix[it]}B", toDouble() / 2.0.pow(it * 10.0))
    }

Применение:

println("170:        " + 170.formatAsFileSize)
println("14356:      " + 14356.formatAsFileSize)
println("968542985:  " + 968542985.formatAsFileSize)
println("8729842496: " + 8729842496.formatAsFileSize)

println("file: " + file.formatSize)

Результат:

170:        170 B
14356:      14.0 KB
968542985:  923.67 MB
8729842496: 8.13 GB

file: 6.15 MB

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);
}

Byte Units позволяет сделать это так:

long input1 = 1024;
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));

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

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);

Org .springframework.util.unit.DataSize может соответствовать этому требованию, по крайней мере, для расчета. Тогда подойдет и простой декоратор.

    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 "???";
    }

Еще одно краткое решение без цикла, но с форматированием, зависящим от локали и правильными двоичными префиксами:

      import java.util.Locale;

public final class Bytes {

  private Bytes() {
  }

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

Тестовое задание:

      Locale locale = Locale.getDefault()
System.out.println(Bytes.format(1L, locale))
System.out.println(Bytes.format(2L * 1024, locale))
System.out.println(Bytes.format(3L * 1024 * 1024, locale))
System.out.println(Bytes.format(4L * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(5L * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(6L * 1024 * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(Long.MAX_VALUE, locale))

Выход:

      1 B
2.0 KiB
3.0 MiB
4.0 GiB
5.0 GiB
6.0 PiB
8.0 EiB

Теперь доступна одна библиотека, которая содержит форматирование модулей. Я добавил его в библиотеку 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

Для любителей kotlin используйте это расширение

      fun Long.readableFormat(): String {
    if (this <= 0 ) return "0"
    val units = arrayOf("B", "kB", "MB", "GB", "TB")
    val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
    return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
}

Теперь используйте

      val size : Long = 90836457
val readbleString = size.readableFormat()

Другой подход

      val Long.formatSize : String
    get() {
        if (this <= 0) return "0"
        val units = arrayOf("B", "kB", "MB", "GB", "TB")
        val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
        return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
    }

Теперь используйте

      val size : Long = 90836457
val readbleString = size.formatSize 

Я знаю, что уже поздно обновлять этот пост! но я повеселился с этим:

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

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

В случайном случае это экономит кому-то немного времени, или, может быть, просто для развлечения, вот версия 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)
}
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]; вернуть sizeToReturn; }

Я использую немного измененный метод, чем принятый ответ:

public static String formatFileSize(long bytes) {
        if (bytes <= 0) return "";
        if (bytes < 1000) return bytes + " B";
        CharacterIterator ci = new StringCharacterIterator("kMGTPE");
        while (bytes >= 99_999) {
            bytes /= 1000;
            ci.next();
        }
        return String.format(Locale.getDefault(), "%.1f %cB", bytes / 1000.0, ci.current());
    }

Потому что я хочу увидеть другой результат:

                              SI   

                   0:            <--------- instead of 0 B
                  27:       27 B     
                 999:      999 B   
                1000:     1.0 kB   
                1023:     1.0 kB   
                1024:     1.0 kB 
                1728:     1.7 kB   
              110592:     0.1 MB <--------- instead of 110.6 kB
             7077888:     7.1 MB  
           452984832:     0.5 GB <--------- instead of 453.0 MB
         28991029248:    29.0 GB  

Вы можете использовать StringUtilsTraditionalBinarPrefix:

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

Вот эквивалент C# .net для правильного согласованного ответа Java выше. (есть еще один, который имеет более короткие коды)

    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#.

Если на Android, вы можете просто вызвать один из статических методовandroid.text.Format.Formatter.

https://developer.android.com/reference/android/text/format/Formatter

На практике мегабайты достаточно удобочитаемы для человека.

      long l = 1367343104l;
    
String s = String.format("%dm", l / 1024 / 1024);

1304м

Вот преобразование aioobe в Kotlin:

/**
 * https://stackru.com/a/3758880/1006741
 */
fun Long.humanReadableByteCountBinary(): String {
    val b = when (this) {
        Long.MIN_VALUE -> Long.MAX_VALUE
        else -> abs(this)
    }
    return when {
        b < 1024L -> "$this B"
        b <= 0xfffccccccccccccL shr 40 -> "%.1f KiB".format(Locale.UK, this / 1024.0)
        b <= 0xfffccccccccccccL shr 30 -> "%.1f MiB".format(Locale.UK, this / 1048576.0)
        b <= 0xfffccccccccccccL shr 20 -> "%.1f GiB".format(Locale.UK, this / 1.073741824E9)
        b <= 0xfffccccccccccccL shr 10 -> "%.1f TiB".format(Locale.UK, this / 1.099511627776E12)
        b <= 0xfffccccccccccccL -> "%.1f PiB".format(Locale.UK, (this shr 10) / 1.099511627776E12)
        else -> "%.1f EiB".format(Locale.UK, (this shr 20) / 1.099511627776E12)
    }
}

Может быть, вы можете использовать этот код (в C#):

        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";

Ниже приведен быстрый, простой и читаемый фрагмент кода для достижения этой цели:

      /**
 * Converts byte size to human readable strings (also declares useful constants)
 *
 * @see <a href="https://en.wikipedia.org/wiki/File_size">File size</a>
 */
@SuppressWarnings("SpellCheckingInspection")
public class HumanReadableSize {
    public static final double
            KILO = 1000L, // 1000 power 1 (10 power 3)
            KIBI = 1024L, // 1024 power 1 (2 power 10)
            MEGA = KILO * KILO, // 1000 power 2 (10 power 6)
            MEBI = KIBI * KIBI, // 1024 power 2 (2 power 20)
            GIGA = MEGA * KILO, // 1000 power 3 (10 power 9)
            GIBI = MEBI * KIBI, // 1024 power 3 (2 power 30)
            TERA = GIGA * KILO, // 1000 power 4 (10 power 12)
            TEBI = GIBI * KIBI, // 1024 power 4 (2 power 40)
            PETA = TERA * KILO, // 1000 power 5 (10 power 15)
            PEBI = TEBI * KIBI, // 1024 power 5 (2 power 50)
            EXA = PETA * KILO, // 1000 power 6 (10 power 18)
            EXBI = PEBI * KIBI; // 1024 power 6 (2 power 60)

    private static final DecimalFormat df = new DecimalFormat("#.##");

    public static String binaryBased(long size) {
        if (size < 0) {
            throw new IllegalArgumentException("Argument cannot be negative");
        } else if (size < KIBI) {
            return df.format(size).concat("B");
        } else if (size < MEBI) {
            return df.format(size / KIBI).concat("KiB");
        } else if (size < GIBI) {
            return df.format(size / MEBI).concat("MiB");
        } else if (size < TEBI) {
            return df.format(size / GIBI).concat("GiB");
        } else if (size < PEBI) {
            return df.format(size / TEBI).concat("TiB");
        } else if (size < EXBI) {
            return df.format(size / PEBI).concat("PiB");
        } else {
            return df.format(size / EXBI).concat("EiB");
        }
    }

    public static String decimalBased(long size) {
        if (size < 0) {
            throw new IllegalArgumentException("Argument cannot be negative");
        } else if (size < KILO) {
            return df.format(size).concat("B");
        } else if (size < MEGA) {
            return df.format(size / KILO).concat("KB");
        } else if (size < GIGA) {
            return df.format(size / MEGA).concat("MB");
        } else if (size < TERA) {
            return df.format(size / GIGA).concat("GB");
        } else if (size < PETA) {
            return df.format(size / TERA).concat("TB");
        } else if (size < EXA) {
            return df.format(size / PETA).concat("PB");
        } else {
            return df.format(size / EXA).concat("EB");
        }
    }
}

Примечание:

  1. Приведенный выше код подробен и понятен.
    • Он не использует циклы (циклы следует использовать только тогда, когда вы не знаете, сколько раз вам нужно выполнить итерацию во время компиляции)
    • Он не делает ненужных вызовов библиотеки ( StringBuilder, Math так далее.)
  2. Вышеупомянутый код работает быстро и использует очень мало памяти. Судя по тестам, проведенным на моей персональной облачной машине начального уровня, он самый быстрый (в этих случаях производительность не имеет значения, но все же)
  3. Приведенный выше код - это модифицированная версия одного из хороших ответов.

Используйте следующую функцию, чтобы получить точную информацию, созданную на основе 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),

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

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

Я обычно так делаю, как вы думаете?

public static String getFileSize(double size) {
    return _getFileSize(size,0,1024);
}

public static String _getFileSize(double size, int i, double base) {
    String units = " KMGTP";
    String unit = (i>0)?(""+units.charAt(i)).toUpperCase()+"i":"";
    if(size<base)
        return size +" "+unit.trim()+"B";
    else {
        size = Math.floor(size/base);
        return _getFileSize(size,++i,base);
    }
}
Другие вопросы по тегам