Comment convertir la taille des octets en format lisible par l'homme en Java?

556

Comment convertir la taille des octets en format lisible par l'homme en Java? Comme 1024 devrait devenir "1 Kb" et 1024 * 1024 devrait devenir "1 Mb".

J'en ai assez d'écrire cette méthode d'utilité pour chaque projet. Existe-t-il des méthodes statiques dans Apache Commons pour cela?

Igor Mukhin
la source
32
Si vous utilisez les unités normalisées, 1024 devrait devenir "1 Ko" et 1024 * 1024 devrait devenir "1 Mo". en.wikipedia.org/wiki/Binary_prefix
Pascal Cuoq
@Pascal: Il devrait y avoir plusieurs fonctions ou une option pour spécifier la base et l'unité.
Aaron Digulla
double possible de la taille du fichier de format en Mo, Go, etc.
Aaron Digulla
3
@Pascal Cuoq: Merci pour la référence. Je ne me suis pas rendu compte avant de l'avoir lu qu'ici, dans l'UE, nous sommes tenus d'utiliser les bons préfixes par la loi.
JeremyP
2
@DerMike Vous avez mentionné que "jusqu'à ce qu'une telle bibliothèque existe". C'est maintenant devenu vrai. :-) stackoverflow.com/questions/3758606/…
Christian Esken

Réponses:

1310

Fait amusant: l'extrait original publié ici était l'extrait Java le plus copié de tous les temps sur Stack Overflow, et il était imparfait. Il a été corrigé mais il est devenu désordonné.

Article complet dans cet article: l' extrait de StackOverflow le plus copié de tous les temps est imparfait!

Source: Formatage de la taille des octets au format lisible par l'homme | Guide de programmation

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

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

Exemple de sortie:

                              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
la source
12
Je préfère 1,0 Ko. Ensuite, il est clair combien de chiffres significatifs la sortie implique. (Cela semble également être le comportement, par exemple, de la ducommande sous Linux.)
aioobe
19
Je pense que chacun devrait noter que dans votre projet, le client souhaite voir les valeurs en base 2 (divisées par 1024) mais avec un préfixe commun. Pas KiB, MiB, GiB etc. Utilisez KB, MB, GB, TB pour cela.
Borys
27
@Borys L'utilisation de "KB" pour signifier "1024 octets" est incorrecte. Ne fais pas ça.
endolith
8
Les lecteurs l'apprendront. Mieux vaut quelque chose qu'ils ne connaissent pas et peuvent apprendre que d'avoir quelque chose de mal. Pour écrire KB, un utilisateur qui le connaît attendra 1000 et un utilisateur qui ne le sera pas attendra 1024.
kap
16
Réponse entièrement réécrite. Bon nombre des commentaires ci-dessus sont obsolètes.
aioobe
305

FileUtils.byteCountToDisplaySize(long size)fonctionnerait si votre projet pouvait dépendre org.apache.commons.io.

JavaDoc pour cette méthode

user601806
la source
18
J'ai déjà commons-io sur mon projet, mais j'ai fini par utiliser le code d'Aioobe, en raison du comportement d'arrondi (voir le lien pour JavaDoc)
Iravanchi
3
existe-t-il un utilitaire pour effectuer l'opération inverse. Obtenir le nombre d'octets à partir du nombre d'octets lisibles par l'homme?
arunmoezhi
6
Malheureusement, cette fonction n'est pas sensible aux paramètres régionaux; en français, par exemple, ils appellent toujours les octets "octets", donc si vous voulez afficher un fichier de 100 Ko à un utilisateur français, le libellé correct serait 100 Ko.
Tacroy
@Tacroy Vous pouvez obtenir une sortie d'octets avec UnitFormatter dans la bibliothèque triava. Vous pouvez transmettre n'importe quelle unité en octets, watts ou octets. Exemple, légèrement modifié à partir des exemples de github.com/trivago/triava : UnitFormatter.formatAsUnit (1126, UnitSystem.SI, "o"); // = "1,13 ko" Plus d'exemples dans: stackoverflow.com/questions/3758606/…
Christian Esken
5
cela arrondit au Go le plus proche lorsque> 1 Go, ce qui signifie que la précision que vous en
retirez
180

Utiliser la classe intégrée Android

Pour Android, il existe un formateur de classe . Une seule ligne de code et vous avez terminé.

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

C'est comme formatFileSize(), mais en essayant de générer des nombres plus courts (montrant moins de décimales).

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

Formate une taille de contenu sous forme d'octets, kilo-octets, mégaoctets, etc.

AZ_
la source
12
devrait être la meilleure réponse pour ANDROID définitivement. Aucune bibliothèque supplémentaire nécessaire. +1
dieter
11
Je déteste le fait que tu doives passer Context.
Jared Burrows
4
Devrait être la meilleure réponse pour ANDROID définitivement.
shridutt kothari
5
Vous passez dans le contexte afin qu'il soit traduit dans les paramètres régionaux actuels de l'utilisateur. Sinon, ce ne serait pas une fonction très utile.
phreakhead
7
J'utilisais la réponse acceptée avant de le savoir. Juste pour être noté, dans Build.VERSION_CODES.N et versions antérieures, des puissances de 1024 sont utilisées à la place, avec KB = 1024 octets, MB = 1 048 576 octets, etc. À partir de O, les préfixes sont utilisés dans leur signification standard dans le système SI , donc kB = 1 000 octets, Mo = 1 000 000 octets, etc.
HendraWD
57

Nous pouvons complètement éviter d'utiliser les méthodes slow Math.pow()et Math.log()sans sacrifier la simplicité puisque le facteur entre les unités (par exemple B, KB, MB etc.) est 1024, ce qui est 2 ^ 10. La Longclasse a une numberOfLeadingZeros()méthode pratique que nous pouvons utiliser pour dire dans quelle unité la valeur de taille se situe.

Point clé: les unités de taille ont une distance de 10 bits (1024 = 2 ^ 10), ce qui signifie que la position du 1 bit le plus élevé - ou en d'autres termes le nombre de zéros en tête - diffère de 10 (octets = Ko * 1024, Ko = Mo * 1024 etc.).

Corrélation entre le nombre de zéros en tête et l'unité de taille:

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

Le code final:

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
la source
24

J'ai posé la même question récemment:

Formater la taille du fichier en Mo, Go, etc.

Bien qu'il n'y ait pas de réponse prête à l'emploi, je peux vivre avec la solution:

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

Code de test:

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

Sortie (sur mes paramètres régionaux allemands):

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

Modifier: j'ai ouvert un problème demandant cette fonctionnalité pour Google Guava . Peut-être que quelqu'un voudrait le soutenir.

Sean Patrick Floyd
la source
2
Pourquoi 0 est-il une taille de fichier non valide?
aioobe
@aioobe c'était dans mon cas d'utilisation (affichant la taille d'un fichier téléchargé), mais ce n'est sans doute pas universel
Sean Patrick Floyd
Si vous modifiez la dernière ligne pour retourner NumberFormat.getFormat ("#, ## 0. #"). Format (result) + "" + unit; ça marche aussi dans GWT! Merci pour cela, ce n'est toujours pas à Goyave.
tom
9

Il s'agit d'une version modifiée de la réponse d' Aioobe .

Changements:

  • Locale, car certaines langues utilisent .et d'autres ,comme point décimal.
  • code lisible par l'homme

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
la source
C'est un peu un résultat mitigé de transmettre un paramètre Locale juste pour les symboles de séparation, mais ne localisez pas également l'unité pour tenir compte des langues qui utilisent également un symbole différent pour les octets, comme le français.
Nzall
@Nzall Voulez-vous dire l'octet? Wikipédia déclare que ce n'est plus courant. Sinon, avez-vous une référence?
Christian Strempfer
7

Si vous utilisez Android, vous pouvez simplement utiliser android.text.format.Formatter.formatFileSize () .

Alternativement, voici une solution basée sur ce post populaire :

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

Ou à 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()
}
développeur android
la source
Vous semblez avoir une erreur off-by-one dans votre boucle for. Je pense que ça devrait l'être unitsCountet non unitsCount-1.
aioobe
@aioobe mais cela signifie que la boucle peut s'arrêter lorsque i == unitsCount, ce qui signifie que i == 6, ce qui signifie que "charAt" échouera ...
développeur Android
if(result<unit) break;va démarrer avant cela. Pas de soucis. (Si vous le testez, vous remarquerez que vous pouvez ignorer entièrement la condition de boucle.)
aioobe
@aioobe Correct, c'est à cause de l'hypothèse (qui est correcte) que je gère le type de variable "long". En outre, il est basé sur l'hypothèse que les unités seront au moins ce que j'ai écrites. Si vous utilisez moins d'unités, cela produira des résultats étranges (préférera des valeurs inférieures à 1 plutôt que des valeurs supérieures à 1000).
développeur Android
@aioobe Correct. Je le réparerai. BTW, votre algorithme peut également fournir un résultat étrange. essayez de lui donner "999999, vrai" comme arguments. il affichera "1000,0 kB", donc il est arrondi, mais quand les gens le voient, ils peuvent se demander: pourquoi ne peut-il pas afficher 1 Mo, car 1000 Ko = 1 Mo ... Comment pensez-vous que cela devrait être géré? C'est à cause du String.format, mais je ne sais pas comment il devrait être corrigé.
développeur Android
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
la source
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
la source
J'aime ça parce que c'est facile à suivre et à comprendre.
Joshua Pinter
6

Unités d'octets vous permet de le faire comme ceci:

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

J'ai écrit une autre bibliothèque appelée unités de stockage qui vous permet de le faire comme ceci:

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

Si vous souhaitez forcer une certaine unité, procédez comme suit:

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

Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
Sebastian Hoß
la source
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
la source
3

Il existe désormais une bibliothèque contenant le formatage des unités. Je l'ai ajouté à la bibliothèque triava , car la seule autre bibliothèque existante semble être une pour Android.

Il peut formater des nombres avec une précision arbitraire, dans 3 systèmes différents (SI, IEC, JEDEC) et diverses options de sortie. Voici quelques exemples de code issus des tests unitaires triava :

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

Impression du kilo exact, des méga valeurs (ici avec W = Watt):

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

Vous pouvez passer un DecimalFormat pour personnaliser la sortie:

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

Pour des opérations arbitraires sur des kilos ou des méga valeurs, vous pouvez les diviser en composants:

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

Je sais qu'il est trop tard pour mettre à jour ce post! mais je me suis amusé avec ça:

Créez une interface:

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

Créer une classe 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.#");
}
}

Appeler:

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

Production:

21.4kB
2GB
Ahmad AlMughrabi
la source
2

Dans le cas contraire, cela fait gagner du temps à quelqu'un, ou peut-être juste pour un peu de plaisir, voici une version Go. Par souci de simplicité, je n'ai inclus que le cas de sortie binaire.

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

Ajoutez simplement plus d'unités de fichier (le cas échéant), et vous verrez la taille de l'unité jusqu'à cette unité (si votre fichier a autant de longueur) System.out.println ("Taille de fichier au format approprié:" + octets + "" + fileSizeUnits [indice]); sizeToReturn = String.valueOf (bytes) + "" + fileSizeUnits [index]; return sizeToReturn; }

Vishwajit R. Shinde
la source
1

Voici l'équivalent C # .net pour la réponse de consensus correcte Java ci-dessus. (il y a un autre ci-dessous qui a des codes plus courts)

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

Techniquement parlant, si nous nous en tenons aux unités SI, cette routine fonctionne pour toute utilisation régulière des nombres. Il existe de nombreuses autres bonnes réponses d'experts. Supposons que vous effectuez une liaison de données de nombres sur des vues de grille, cela vaut la peine de vérifier leurs routines optimisées pour les performances.

PS: Publié parce que cette question / réponse est apparue en tête de la recherche Google pendant que je fais un projet C #.

Chan Fun Chiat
la source
1

Vous pouvez utiliser StringUtils les s de TraditionalBinarPrefix:

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

peu vieux mais, ... org.springframework.util.unit.DataSize pourrait convenir à cette exigence au moins pour le calcul, alors un simple décorateur fera l'affaire

Tama
la source
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
la source
Cette réponse, bien qu'elle fonctionne, est un complément à une réponse précédente dans ce fil de @ user601806: stackoverflow.com/a/4888400/3987745 Pour que cette réponse fonctionne, vous avez besoin d'Apache Commons IO ( commons.apache.org/proper/ communs-io ) dépendance.
Edward Quichotte
0

Avez-vous essayé JSR 363 ? Ses modules d'extension d'unité comme Unicode CLDR (dans GitHub: uom-systems ) font tout cela pour vous.

Vous pouvez utiliser MetricPrefixinclus dans chaque implémentation ou BinaryPrefix(comparable à certains des exemples ci-dessus) et si vous vivez et travaillez par exemple en Inde ou dans un pays voisin, IndianPrefix(également dans le module commun de uom-systems) vous permet d'utiliser et de formater "Crore Octets "ou" octets Lakh ", aussi.

Werner Keil
la source
0

Vous pouvez peut-être utiliser ce code (en 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
la source
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
la source
0

Utilisez la fonction suivante pour obtenir des informations exactes, générées en prenant la base du ATM_CashWithdrawlconcept.

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

Je viens de modifier le code de facebookarchive-StringUtils pour obtenir le format ci-dessous. Même format que vous obtiendrez lorsque vous utiliserez 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;
}

Exemple d'utilisation des méthodes ci-dessus:

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

Octets pour obtenir au-dessus du format

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

Afin d'afficher l'heure dans un format lisible par l'homme, utilisez cette fonction millisToShortDHMS(long duration).

Yash
la source
0

voici la conversion de @aioobe convertie en 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
la source