如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
当前回答
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 "???";
}
其他回答
字节单位允许你这样做:
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));
我写了另一个叫做storage-units的库,它允许你这样做:
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);
如果你想强制某个单位,可以这样做:
String formattedUnit9 = StorageUnits.formatAsKibibyte(input2);
String formattedUnit10 = StorageUnits.formatAsCommonMegabyte(input2);
Assert.assertEquals("1024.00 KiB", formattedUnit9);
Assert.assertEquals("1.00 MB", formattedUnit10);
如果你使用Android,你可以简单地使用Android .text.format. formatter . formatfilesize()。它的优点是易于使用,并且它取决于区域设置,以便为用户更好地显示它。缺点是它不处理EB,而且它只用于公制单位(每个Kilo是1000字节,不能作为1024字节使用)。
或者,这里有一个基于这篇热门文章的解决方案:
interface BytesFormatter {
/**called when the type of the result to format is Long. Example: 123KB
* @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
* available units and their order: B,K,M,G,T,P,E
* @param isMetric true if each kilo==1000, false if kilo==1024
* */
fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String
/**called when the type of the result to format is Double. Example: 1.23KB
* @param unitPowerIndex the unit-power we need to format to. Examples: 0 is bytes, 1 is kb, 2 is mb, etc...
* available units and their order: B,K,M,G,T,P,E
* @param isMetric true if each kilo==1000, false if kilo==1024
* */
fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String
}
/**
* formats the bytes to a human readable format, by providing the values to format later in the unit that we've found best to fit it
*
* @param isMetric true if each kilo==1000, false if kilo==1024
* */
fun bytesIntoHumanReadable(
@IntRange(from = 0L) bytesToFormat: Long, bytesFormatter: BytesFormatter,
isMetric: Boolean = true
): String {
val units = if (isMetric) 1000L else 1024L
if (bytesToFormat < units)
return bytesFormatter.onFormatLong(bytesToFormat, 0, isMetric)
var bytesLeft = bytesToFormat
var unitPowerIndex = 0
while (unitPowerIndex < 6) {
val newBytesLeft = bytesLeft / units
if (newBytesLeft < units) {
val byteLeftAsDouble = bytesLeft.toDouble() / units
val needToShowAsInteger =
byteLeftAsDouble == (bytesLeft / units).toDouble()
++unitPowerIndex
if (needToShowAsInteger) {
bytesLeft = newBytesLeft
break
}
return bytesFormatter.onFormatDouble(byteLeftAsDouble, unitPowerIndex, isMetric)
}
bytesLeft = newBytesLeft
++unitPowerIndex
}
return bytesFormatter.onFormatLong(bytesLeft, unitPowerIndex, isMetric)
}
Sample usage:
// val valueToTest = 2_000L
// val valueToTest = 2_000_000L
// val valueToTest = 2_000_000_000L
// val valueToTest = 9_000_000_000_000_000_000L
// val valueToTest = 9_200_000_000_000_000_000L
val bytesToFormat = Random.nextLong(Long.MAX_VALUE)
val bytesFormatter = object : BytesFormatter {
val numberFormat = NumberFormat.getNumberInstance(Locale.ROOT).also {
it.maximumFractionDigits = 2
it.minimumFractionDigits = 0
}
private fun formatByUnit(formattedNumber: String, threePowerIndex: Int, isMetric: Boolean): String {
val sb = StringBuilder(formattedNumber.length + 4)
sb.append(formattedNumber)
val unitsToUse = "B${if (isMetric) "k" else "K"}MGTPE"
sb.append(unitsToUse[threePowerIndex])
if (threePowerIndex > 0)
if (isMetric) sb.append('B') else sb.append("iB")
return sb.toString()
}
override fun onFormatLong(valueToFormat: Long, unitPowerIndex: Int, isMetric: Boolean): String {
return formatByUnit(String.format("%,d", valueToFormat), unitPowerIndex, isMetric)
}
override fun onFormatDouble(valueToFormat: Double, unitPowerIndex: Int, isMetric: Boolean): String {
//alternative for using numberFormat :
//val formattedNumber = String.format("%,.2f", valueToFormat).let { initialFormattedString ->
// if (initialFormattedString.contains('.'))
// return@let initialFormattedString.dropLastWhile { it == '0' }
// else return@let initialFormattedString
//}
return formatByUnit(numberFormat.format(valueToFormat), unitPowerIndex, isMetric)
}
}
Log.d("AppLog", "formatting of $bytesToFormat bytes (${String.format("%,d", bytesToFormat)})")
Log.d("AppLog", bytesIntoHumanReadable(bytesToFormat, bytesFormatter))
Log.d("AppLog", "Android:${android.text.format.Formatter.formatFileSize(this, bytesToFormat)}")
下面是从aioobe转换到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)
}
}
你可以使用StringUtils的TraditionalBinarPrefix:
public static String humanReadableInt(long number) {
return TraditionalBinaryPrefix.long2String(number, ””, 1);
}
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);
}