Jak przekonwertować rozmiar bajtu na format czytelny dla człowieka w Javie?

556

Jak przekonwertować rozmiar bajtu na format czytelny dla człowieka w Javie? Podobnie 1024 powinno stać się „1 Kb”, a 1024 * 1024 powinno stać się „1 Mb”.

Mam dość pisania tej metody narzędziowej dla każdego projektu. Czy istnieją w tym celu jakieś metody statyczne w Apache Commons ?

Igor Mukhin
źródło
32
Jeśli używasz standardowych jednostek, 1024 powinno stać się „1KiB”, a 1024 * 1024 powinno stać się „1MiB”. en.wikipedia.org/wiki/Binary_prefix
Pascal Cuoq
@Pascal: Powinna istnieć kilka funkcji lub opcja określania bazy i jednostki.
Aaron Digulla,
możliwy duplikat formatu Formatuj jako MB, GB itp.
Aaron Digulla
3
@Pascal Cuoq: Dzięki za odniesienie. Dopóki nie przeczytałem, nie zdawałem sobie sprawy, że tutaj, w UE, jesteśmy zobowiązani do używania poprawnych prefiksów przez prawo.
JeremyP,
2
@DerMike Wspomniałeś, że „dopóki taka biblioteka nie istnieje”. To stało się teraz prawdą. :-) stackoverflow.com/questions/3758606/…
Christian Esken

Odpowiedzi:

1310

Ciekawostka: opublikowany tutaj oryginalny fragment kodu był najczęściej kopiowanym fragmentem kodu Java w historii na stosie przepełnienia stosu i był wadliwy. Zostało naprawione, ale zrobiło się bałagan.

Pełna historia w tym artykule: Najczęściej kopiowany fragment StackOverflow wszechczasów jest wadliwy!

Źródło: Formatowanie rozmiaru bajtu na format czytelny dla człowieka | Programowanie. Przewodnik

SI (1 k = 1000)

public static String humanReadableByteCountSI(long bytes) {
    if (-1000 < bytes && bytes < 1000) {
        return bytes + " B";
    }
    CharacterIterator ci = new StringCharacterIterator("kMGTPE");
    while (bytes <= -999_950 || bytes >= 999_950) {
        bytes /= 1000;
        ci.next();
    }
    return String.format("%.1f %cB", bytes / 1000.0, ci.current());
}

Binarny (1 K = 1024)

public static String humanReadableByteCountBin(long bytes) {
    long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
    if (absB < 1024) {
        return bytes + " B";
    }
    long value = absB;
    CharacterIterator ci = new StringCharacterIterator("KMGTPE");
    for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
        value >>= 10;
        ci.next();
    }
    value *= Long.signum(bytes);
    return String.format("%.1f %ciB", value / 1024.0, ci.current());
}

Przykładowe dane wyjściowe:

                              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)
aioobe
źródło
12
Wolę 1,0 KB. Wtedy jasne jest, ile znaczących liczb pociąga za sobą wynik. (Wydaje się, że jest to na przykład zachowanie dupolecenia w Linuksie.)
aioobe,
19
Myślę, że każdy powinien zauważyć, że w twoim projekcie klient chce zobaczyć wartości w bazie 2 (podzielone przez 1024), ale ze wspólnym prefiksem. Nie KiB, MiB, GiB itp. Użyj do tego KB, MB, GB, TB.
Borys
27
@Borys Niepoprawne użycie „KB” w celu oznaczenia „1024 bajtów”. Nie rób tego
endolith,
8
Czytelnicy się tego nauczą. Lepiej coś, czego nie znają i mogą się tego nauczyć niż mieć coś złego. Pisanie KB użytkownik, który jest zaznajomiony z tym oczekuje 1000 i użytkownik, który nie zna się spodziewać 1024.
kap
16
Odpowiedź przepisana całkowicie. Wiele z powyższych komentarzy jest nieaktualnych.
aioobe,
304

FileUtils.byteCountToDisplaySize(long size)działałoby, jeśli Twój projekt może polegać org.apache.commons.io.

JavaDoc dla tej metody

użytkownik601806
źródło
18
Mam już commons-io w moim projekcie, ale skończyło się na użyciu kodu aioobe, ze względu na zachowanie zaokrąglania (patrz link do JavaDoc)
Iravanchi
3
czy jest narzędzie do wykonania operacji odwrotnej? Uzyskiwanie liczby bajtów z czytelnej dla człowieka liczby bajtów?
arunmoezhi
6
Niestety ta funkcja nie rozpoznaje ustawień regionalnych; na przykład w języku francuskim zawsze nazywają bajty „oktetami”, więc jeśli zamierzasz wyświetlić plik o rozmiarze 100 KB użytkownikowi francuskiemu, poprawna etykieta to 100 Ko.
Tacroy,
@Tacroy Wyjście oktetów można uzyskać za pomocą UnitFormatter w bibliotece triava. Możesz przekazać dowolną jednostkę dla bajtów, watów lub oktetów. Przykład, nieznacznie zmodyfikowany z przykładów w github.com/trivago/triava : UnitFormatter.formatAsUnit (1126, UnitSystem.SI, „o”); // = "1.13 ko" Więcej przykładów w: stackoverflow.com/questions/3758606/...
Christian Esken
5
to zaokrągla do najbliższej gb gdy> 1 GB, co oznacza, że precyzja wydostać się z niego różni
tksfz
180

Użyj wbudowanej klasy Androida

W systemie Android istnieje klasowy moduł formatujący . Tylko jeden wiersz kodu i gotowe.

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

To tak formatFileSize(), ale próbuje wygenerować krótsze liczby (pokazujące mniej miejsc po przecinku).

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

Formatuje rozmiar zawartości w postaci bajtów, kilobajtów, megabajtów itp.

AZ_
źródło
12
zdecydowanie powinna być najlepszą odpowiedzią dla ANDROIDA. Żadne dodatkowe biblioteki nie są potrzebne. +1
dieter
11
Nienawidzę faktu, że musicie wejść Context.
Jared Burrows,
4
Zdecydowanie powinna być najlepszą odpowiedzią dla ANDROIDA.
shridutt kothari,
5
Przekazujesz kontekst, więc jest on tłumaczony na bieżące ustawienia regionalne użytkownika. W przeciwnym razie nie byłaby to bardzo przydatna funkcja.
phreakhead
7
Użyłem zaakceptowanej odpowiedzi, zanim się zorientowałem. Należy zauważyć, że w Build.VERSION_CODES.N i wcześniejszych użyto mocy 1024, z KB = 1024 bajtów, MB = 1 048 576 bajtów itp. Od O, prefiksy są używane w ich standardowych znaczeniach w systemie SI , więc kB = 1000 bajtów, MB = 1 000 000 bajtów itp.
HendraWD
57

Możemy całkowicie uniknąć używania metody slow Math.pow()i Math.log()metod bez poświęcania prostoty, ponieważ współczynnik między jednostkami (np. B, KB, MB itp.) Wynosi 1024, czyli 2 ^ 10. LongKlasa posiada wygodny numberOfLeadingZeros()sposób, który możemy wykorzystać, aby powiedzieć, która jednostka wartość wielkości przypada.

Kluczowy punkt: Jednostki rozmiaru mają odległość 10 bitów (1024 = 2 ^ 10), co oznacza pozycję najwyższego 1 bitu - lub innymi słowy liczby zer wiodących - różnią się o 10 (Bajty = KB * 1024, KB = MB * 1024 itd.).

Korelacja między liczbą zer wiodących a jednostką wielkości:

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

Ostateczny kod:

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));
}
icza
źródło
24

Ostatnio zadałem to samo pytanie:

Sformatuj rozmiar pliku jako MB, GB itp

Chociaż nie ma gotowej odpowiedzi, mogę żyć z rozwiązaniem:

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

Kod testowy:

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

Dane wyjściowe (w moim języku niemieckim):

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

Edycja: otworzyłem problem z prośbą o tę funkcję dla Google Guava . Być może ktoś zechce to wesprzeć.

Sean Patrick Floyd
źródło
2
Dlaczego 0 jest nieprawidłowym rozmiarem pliku?
aioobe
@ aioobe to było w moim przypadku użycia (wyświetlanie rozmiaru przesłanego pliku), ale prawdopodobnie nie jest to uniwersalne
Sean Patrick Floyd
Jeśli zmienisz ostatni wiersz, aby zwrócić NumberFormat.getFormat ("#, ## 0. #"). Format (wynik) + "" + jednostka; działa również w GWT! Dzięki za to, wciąż nie ma go na Guawie.
tom
9

To jest zmodyfikowana wersja odpowiedzi aioobe .

Zmiany:

  • Localeparametr, ponieważ niektóre języki używają, .a inne ,jako przecinek dziesiętny.
  • kod czytelny dla człowieka

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);
}
Christian Strempfer
źródło
Przekazanie parametru Locale tylko dla symboli separatora jest nieco mieszane, ale nie należy również lokalizować urządzenia w celu uwzględnienia języków, które również używają innego symbolu dla bajtów, takich jak francuski.
Nzall
@Nzall Czy masz na myśli oktet? Wikipedia twierdzi, że to już nie jest powszechne. W przeciwnym razie masz referencje?
Christian Strempfer
7

Jeśli używasz Androida, możesz po prostu użyć android.text.format.Formatter.formatFileSize () .

Alternatywnie, oto rozwiązanie oparte na tym popularnym poście :

  /**
   * 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;
    }

Lub w Kotlin:

/**
 * formats the bytes to a human readable format
 *
 * @param si true if each kilo==1000, false if kilo==1024
 */
@SuppressLint("DefaultLocale")
fun humanReadableByteCount(bytes: Long, si: Boolean): String? {
    val unit = if (si) 1000.0 else 1024.0
    if (bytes < unit)
        return "$bytes B"
    var result = bytes.toDouble()
    val unitsToUse = (if (si) "k" else "K") + "MGTPE"
    var i = 0
    val unitsCount = unitsToUse.length
    while (true) {
        result /= unit
        if (result < unit || i == unitsCount - 1)
            break
        ++i
    }
    return with(StringBuilder(9)) {
        append(String.format("%.1f ", result))
        append(unitsToUse[i])
        if (si) append('B') else append("iB")
    }.toString()
}
programista Androida
źródło
Wygląda na to, że w pętli for występuje błąd „jeden po drugim”. Myślę, że tak powinno być unitsCounti nie unitsCount-1.
aioobe
@ aioobe, ale oznacza to, że pętla może się zatrzymać, gdy i == unitsCount, co oznacza, że ​​i == 6, co oznacza, że ​​„charAt” nie powiedzie się ...
programista Androida
if(result<unit) break;wpakuje się wcześniej. Bez obaw. (Jeśli go przetestujesz, zauważysz, że możesz całkowicie pominąć warunek pętli for.)
aioobe
@ aioobe Prawidłowo, to z powodu założenia (które jest poprawne), że obsługuję typ zmiennej „długiej”. Opiera się również na założeniu, że jednostki będą co najmniej tym, co napisałem. Jeśli użyjesz mniej jednostek, spowoduje to dziwne wyniki (wolisz wartości mniejsze niż 1, a nie większe niż 1000).
programista Androida
@aioobe Correct. Naprawię to. BTW, twój algorytm może również dać dziwny wynik. spróbuj podać jako „999999, prawda” jako argumenty. pokaże „1000,0 kB”, więc jest zaokrąglone, ale kiedy ludzie to zobaczą, mogą się zastanawiać: dlaczego nie może pokazać 1 MB, ponieważ 1000 KB = 1 MB ... Jak myślisz, jak należy to zrobić? Jest to spowodowane formatem String.format, ale nie jestem pewien, jak to naprawić.
programista Androida
6

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);
}
Lars Bohl
źródło
6
  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";
        }
    }
Sujith Manjavana
źródło
Lubię to, ponieważ jest łatwe do naśladowania i łatwe do zrozumienia.
Joshua Pinter
6

Byte Units pozwala ci to zrobić w następujący sposób:

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

Napisałem inną bibliotekę o nazwie Storage-Units, która pozwala ci to zrobić w następujący sposób:

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

Jeśli chcesz zmusić określoną jednostkę, zrób to:

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

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
Sebastian Hoß
źródło
5
    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 "???";
    }
XXX
źródło
3

Dostępna jest teraz jedna biblioteka, która zawiera formatowanie jednostek. Dodałem go do triavy biblioteki , ponieważ jedyną istniejącą biblioteką wydaje się być jedna dla Androida.

Może formatować liczby z dowolną dokładnością, w 3 różnych systemach (SI, IEC, JEDEC) i różnych opcjach wyjściowych. Oto kilka przykładów kodu z testów jednostkowych triava :

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

Drukowanie dokładnych kilogramów, mega wartości (tutaj z W = Watt):

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

Możesz przekazać DecimalFormat, aby dostosować dane wyjściowe:

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

W przypadku dowolnych operacji na kilogramach lub mega wartościach możesz podzielić je na komponenty:

UnitComponent uc = new  UnitComponent(123_345_567_789L, UnitSystem.SI);
int kilos = uc.kilo(); // 567
int gigas = uc.giga(); // 123
Christian Esken
źródło
2

Wiem, że jest za późno na aktualizację tego postu! ale dobrze się z tym bawiłem:

Utwórz interfejs:

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

Utwórz klasę 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.#");
}
}

Nazwać:

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

Wynik:

21.4kB
2GB
Ahmad AlMughrabi
źródło
2

W przypadku braku szansy oszczędza to trochę czasu, a może trochę zabawy, oto wersja Go. Dla uproszczenia podałem tylko przypadek wyjścia binarnego.

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-777
źródło
1
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;
    }

Po prostu dodaj więcej jednostek plików (jeśli ich brakuje), a zobaczysz rozmiar jednostki do tej jednostki (jeśli plik ma taką długość) System.out.println („Rozmiar pliku w odpowiednim formacie:„ + bajty + ”” + fileSizeUnits [indeks]); sizeToReturn = String.valueOf (bytes) + "" + fileSizeUnits [index]; return sizeToReturn; }

Vishwajit R. Shinde
źródło
1

Oto odpowiednik C # .net dla poprawnej odpowiedzi konsensusu Java powyżej. (jest inny poniżej, który ma krótsze kody)

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

Technicznie rzecz biorąc, jeśli trzymamy się jednostek SI, ta procedura działa dla każdego regularnego używania liczb. Istnieje wiele innych dobrych odpowiedzi od ekspertów. Załóżmy, że wykonujesz wiązanie danych liczb w widokach siatki, warto sprawdzić z nich procedury zoptymalizowane pod kątem wydajności.

PS: Wysłano, ponieważ to pytanie / odpowiedź pojawiło się na górze w wyszukiwarce Google, gdy wykonuję projekt w języku C #.

Chan Fun Chiat
źródło
1

Można użyć StringUtils S” TraditionalBinarPrefix:

public static String humanReadableInt(long number) {
    return TraditionalBinaryPrefix.long2String(number,””,1);
}
Joe
źródło
1

nieco stary, ale ... org.springframework.util.unit.DataSize może pasować do tego wymagania przynajmniej do obliczeń, wtedy wystarczy prosty dekorator

Tama
źródło
0
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);
Mano Chella
źródło
Ta odpowiedź, chociaż działa, stanowi uzupełnienie poprzedniej odpowiedzi w tym wątku autorstwa @ user601806: stackoverflow.com/a/4888400/3987745 Aby ta odpowiedź zadziałała, potrzebujesz Apache Commons IO ( commons.apache.org/proper/ zależność commons-io ).
Edward Kichot
0

Czy próbowałeś JSR 363 ? Jego moduły rozszerzeń jednostek, takie jak Unicode CLDR (w GitHub: uom-systems ), robią to wszystko za Ciebie.

Możesz użyć MetricPrefixzawartych w każdej implementacji lub BinaryPrefix(porównywalne z niektórymi przykładami powyżej), a jeśli np. Mieszkasz i pracujesz w Indiach lub w pobliskim kraju, IndianPrefix(także we wspólnym module systemów uom), możesz użyć i sformatować „Crore Bajty ”lub„ Lakh Bytes ”też.

Werner Keil
źródło
0

Może możesz użyć tego kodu (w języku 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";
Jacons Morais
źródło
0
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);
                }
            }
        }
    }
}
Samkov Max
źródło
0

Użyj następującej funkcji, aby uzyskać dokładne informacje, wygenerowane na podstawie ATM_CashWithdrawlkoncepcji.

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

Właśnie zmodyfikowałem kod facebookarchive,StringUtils aby uzyskać poniższy format. Ten sam format, który otrzymasz, gdy używasz 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;
}

Przykładowe użycie powyższych metod:

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

Bajty, aby uzyskać powyżej formatu

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

Aby wyświetlić czas w formacie czytelnym dla człowieka, użyj tej funkcji millisToShortDHMS(long duration).

Yash
źródło
0

oto konwersja z @aioobe przekonwertowana na kotlin

/**
 * https://stackoverflow.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)
    }
}
Kibotu
źródło