如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
当前回答
下面是上面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#项目时,这个问题/答案出现在谷歌搜索的顶部。
其他回答
Kotlin版本通过扩展属性
如果您正在使用Kotlin,那么通过这些扩展名属性格式化文件大小非常容易。它是无循环的,完全基于纯数学。
HumanizeUtils.kt
import java.io.File
import kotlin.math.log2
import kotlin.math.pow
/**
* @author aminography
*/
val File.formatSize: String
get() = length().formatAsFileSize
val Int.formatAsFileSize: String
get() = toLong().formatAsFileSize
val Long.formatAsFileSize: String
get() = log2(if (this != 0L) toDouble() else 1.0).toInt().div(10).let {
val precision = when (it) {
0 -> 0; 1 -> 1; else -> 2
}
val prefix = arrayOf("", "K", "M", "G", "T", "P", "E", "Z", "Y")
String.format("%.${precision}f ${prefix[it]}B", toDouble() / 2.0.pow(it * 10.0))
}
用法:
println("0: " + 0.formatAsFileSize)
println("170: " + 170.formatAsFileSize)
println("14356: " + 14356.formatAsFileSize)
println("968542985: " + 968542985.formatAsFileSize)
println("8729842496: " + 8729842496.formatAsFileSize)
println("file: " + file.formatSize)
结果:
0: 0 B
170: 170 B
14356: 14.0 KB
968542985: 923.67 MB
8729842496: 8.13 GB
file: 6.15 MB
创建接口:
public interface IUnits {
public String format(long size, String pattern);
public long getUnitSize();
}
创建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.#");
}
}
叫它:
class Main {
public static void main(String... args) {
System.out.println(StorageUnits.format(21885));
System.out.println(StorageUnits.format(2188121545L));
}
}
输出:
21.4kB
2GB
现在有一个包含单元格式的库可用。我把它添加到triava库,因为唯一的其他现有库似乎是Android的。
它可以格式化数字与任意精度,在3个不同的系统(SI, IEC, JEDEC)和各种输出选项。下面是来自triava单元测试的一些代码示例:
UnitFormatter.formatAsUnit(1126, UnitSystem.SI, "B");
// = "1.13kB"
UnitFormatter.formatAsUnit(2094, UnitSystem.IEC, "B");
// = "2.04KiB"
打印精确的千克,百万值(这里用W =瓦特):
UnitFormatter.formatAsUnits(12_000_678, UnitSystem.SI, "W", ", ");
// = "12MW, 678W"
你可以传递一个DecimalFormat来定制输出:
UnitFormatter.formatAsUnit(2085, UnitSystem.IEC, "B", new DecimalFormat("0.0000"));
// = "2.0361KiB"
对于kilo或mega值的任意操作,您可以将它们拆分为组件:
UnitComponent uc = new UnitComponent(123_345_567_789L, UnitSystem.SI);
int kilos = uc.kilo(); // 567
int gigas = uc.giga(); // 123
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 "???";
}
这是一个Go版本。为了简单起见,我只包含了二进制输出情况。
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)
}