665 votes

Comment puis-je convertir la taille en bytes en un format lisible par l'homme en Java ?

Comment puis-je convertir la taille en octets en un format lisible en Java ?

Comme 1024 devrait devenir "1 Ko" et 1024*1024 devrait devenir "1 Mo".

Je suis un peu fatigué d'écrire cette méthode utilitaire pour chaque projet. Y a-t-il une méthode statique dans Apache Commons pour ça ?

41 votes

Si vous utilisez les unités normalisées, 1024 devrait devenir "1Kio" et 1024*1024 devrait devenir "1Mio". fr.wikipedia.org/wiki/Préfixe_binaire

0 votes

@Pascal : Il devrait y avoir plusieurs fonctions ou une option pour spécifier la base et l'unité.

0 votes

Possible duplicate de Format file size as MB, GB etc

1466voto

aioobe Points 158466

Fun fact: Le snippet original posté ici était le snippet Java le plus copié de tous les temps sur Stack Overflow, et il était défectueux. Il a été corrigé, mais cela a été compliqué.

Histoire complète dans cet article : Le snippet le plus copié de tous les temps sur Stack Overflow est défectueux!

Source: Formatage de la taille des octets en un format lisible par l'homme | Programming.Guide

SI (1 k = 1 000)

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 Ki = 1 024)

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     BINAIRE

                  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)

1 votes

La seule chose que je n'aime pas à ce sujet est que 1,0 Ko pourrait être affiché de façon plus jolie comme 1 Ko. (C'est pourquoi j'utilise DecimalFormat dans ma réponse)

14 votes

Je préfère 1.0 Ko. Ensuite, il est clair combien de chiffres significatifs représentent la sortie. (Cela semble également être le comportement par exemple de la commande du dans Linux.)

25 votes

Je pense que tout le monde devrait noter que dans votre projet, le client veut voir les valeurs en base 2 (divisées par 1024) mais avec un préfixe commun. Pas KiB, MiB, GiB, etc. Utilisez Ko, Mo, Go, To pour cela.

368voto

user601806 Points 1039

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

JavaDoc pour cette méthode

21 votes

J'ai déjà commons-io sur mon projet, mais j'ai fini par utiliser le code de aioobe, en raison du comportement d'arrondi (voir le lien pour JavaDoc)

3 votes

Y a-t-il un utilitaire pour effectuer l'opération inverse. Obtenir le nombre d'octets à partir du nombre d'octets lisible par l'homme?

7 votes

Malheureusement, cette fonction n'est pas sensible à la localisation ; en français, par exemple, on appelle toujours les octets "octets" donc si vous allez afficher un fichier de 100 Ko à un utilisateur français, le libellé correct serait 100 Ko.

214voto

AZ_ Points 7127

Utiliser une classe intégrée d'Android

Pour Android, il existe une classe, Formatter. Juste une ligne de code et c'est fait.

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

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

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

Elle formate la taille d'un contenu en octets, kilooctets, mégaoctets, etc.

14 votes

Doit être la meilleure réponse pour ANDROID définitivement. Aucune bibliothèque supplémentaire nécessaire. +1

16 votes

Je déteste le fait que vous devez passer par Context.

0 votes

Comment savez-vous cela ?

80voto

icza Points 3857

Nous pouvons éviter complètement d'utiliser les méthodes lentes Math.pow() et Math.log() sans sacrifier la simplicité puisque le facteur entre les unités (par exemple, B, KB, MB, etc.) est 1024 qui est 2^10. La classe Long a une méthode pratique numberOfLeadingZeros() que nous pouvons utiliser pour savoir 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 bit le plus élevé - ou en d'autres termes le nombre de zéros de tête - diffère de 10 (Bytes = KB*1024, KB = MB*1024, etc.).

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

# de zéros de tête

Unité de taille

>53

B (Octets)

>43

KB

>33

MB

>23

GB

>13

TB

>3

PB

<=3

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

28voto

Sean Patrick Floyd Points 109428

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

Format file size as MB, GB, etc.

Bien qu'il n'y ait pas de réponse clé en main, 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));
    }
}

Résultat (sur ma locale allemande) :

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

J'ai ouvert une issue demandant cette fonctionnalité pour Google Guava. Peut-être que quelqu'un voudrait bien le soutenir.

3 votes

Pourquoi la taille de fichier 0 est-elle invalide ?

0 votes

@aioobe c'était dans mon cas d'utilisation (affichage de la taille d'un fichier téléchargé), mais on pourrait soutenir que ce n'est pas universel

0 votes

Si vous modifiez la dernière ligne pour return NumberFormat.getFormat("#,##0.#").format(result) + " " + unit; cela fonctionne également dans GWT ! Merci pour cela, ce n'est toujours pas dans Guava.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X