如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
当前回答
下面是一个快速,简单和可读的代码片段来实现这一点:
/**
* 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");
}
}
}
注意:
上面的代码冗长而简单。 它不使用循环(循环应该只在您不知道在编译期间需要迭代多少次时使用) 它不会进行不必要的库调用(StringBuilder, Math等) 上面的代码是快速的,使用非常少的内存。基于在我个人的入门级云计算机上运行的基准测试,它是最快的(在这些情况下性能并不重要,但仍然如此) 以上代码是一个很好的答案的修改版本
其他回答
下面是上面Java正确的共识答案的c# .NET等价版本 (下面还有一个代码更短的例子):
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);
}
从技术上讲,如果我们坚持使用国际单位制,这个程序适用于任何常规的数字使用。专家们还给出了许多不错的答案。假设您正在对gridview上的数字进行数据绑定,有必要从它们中查看性能优化例程。
PS:这个帖子是因为当我在做一个c#项目时,这个问题/答案出现在谷歌搜索的顶部。
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 "???";
}
我们可以完全避免使用缓慢的Math.pow()和Math.log()方法,而不会牺牲简单性,因为单位之间的因子(例如,B, KB, MB等)是1024,即2^10。Long类有一个方便的numberofleadingzero()方法,我们可以用它来告诉大小值落在哪个单元中。
重点:大小单位的距离为10位(1024 = 2^10),这意味着最高位的位置-换句话说,前导零的数量-相差10(字节= KB*1024, KB = MB*1024,等等)。
前导零数与大小单位的相关性:
# of leading 0's | Size unit |
---|---|
>53 | B (Bytes) |
>43 | KB |
>33 | MB |
>23 | GB |
>13 | TB |
>3 | PB |
<=3 | 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));
}
也许你可以使用下面的代码(在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";
这是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);
}