[java] Java에서 바이트 크기를 사람이 읽을 수있는 형식으로 변환하는 방법은 무엇입니까?

Java에서 바이트 크기를 사람이 읽을 수있는 형식으로 변환하는 방법은 무엇입니까? 1024처럼 “1Kb”가되어야하고 1024 * 1024는 “1Mb”가되어야합니다.

각 프로젝트에 대해이 유틸리티 방법을 작성하는 데 어려움이 있습니다. 이것을 위해 Apache Commons 에 정적 메소드가 있습니까?



답변

재미있는 사실 : 여기에 게시 된 원래 스 니펫은 스택 오버플로에서 가장 많이 복사 된 Java 스 니펫이며 결함이 있습니다. 수정되었지만 지저분 해졌습니다.

이 기사의 전체 기사 : 모든 시간 동안 가장 많이 복사 된 StackOverflow 스 니펫에 결함이 있습니다!

출처 : 바이트 크기를 사람이 읽을 수있는 형식으로 포맷 | 프로그래밍 가이드

SI (1k = 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());
}

이진수 (1K = 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());
}

출력 예 :

                              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)


답변

FileUtils.byteCountToDisplaySize(long size)프로젝트가 의지 할 수 있다면 효과가있을 것입니다 org.apache.commons.io.

이 메소드의 JavaDoc


답변

안드로이드 내장 클래스 사용

안드로이드에는 Formatter 클래스가 있습니다. 한 줄의 코드 만 있으면 완료됩니다.

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

그것은 formatFileSize()같지만 더 짧은 숫자를 생성하려고합니다 (소수를 적게 표시 함).

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

콘텐츠 크기를 바이트, 킬로바이트, 메가 바이트 등의 형식으로 지정합니다.


답변

단위 사이의 요소 (예 : B, KB, MB 등)가 2 ^ 10 인 1024이므로 속도 Math.pow()Math.log()낮추지 않고 속도 와 방법을 사용하지 않아도됩니다. 이 Long클래스에는 numberOfLeadingZeros()크기 값에 속하는 단위를 알려주 는 편리한 메소드가 있습니다.

요점 : 크기 단위의 거리는 10 비트 (1024 = 2 ^ 10)이며 최상위 1 비트의 위치를 ​​의미합니다. 즉, 선행 0수는 10만큼 다릅니다 (바이트 = KB * 1024, KB = MB * 1024 등).

선행 0의 수와 크기 단위의 상관 관계 :

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


답변

최근에 같은 질문을했습니다.

파일 크기를 MB, GB 등으로 지정

기본 답변은 없지만 솔루션으로 살 수 있습니다.

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 에이 기능을 요청 하는 문제를 열었습니다 . 아마도 누군가가 그것을 지원하려고 할 것입니다.


답변

이것은 aioobe ‘s answer의 수정 된 버전입니다 .

변경 사항 :

  • 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를 사용하는 경우 android.text.format.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;
    }

또는 코 틀린에서 :

/**
 * 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()
}