如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
当前回答
也许你可以使用下面的代码(在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";
其他回答
我通常是这样做的:
public static String getFileSize(double size) {
return _getFileSize(size,0,1024);
}
public static String _getFileSize(double size, int i, double base) {
String units = " KMGTP";
String unit = (i>0)?(""+units.charAt(i)).toUpperCase()+"i":"";
if(size<base)
return size +" "+unit.trim()+"B";
else {
size = Math.floor(size/base);
return _getFileSize(size,++i,base);
}
}
如果你使用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)}")
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);
}
datasize至少在计算中可以满足这个需求。那么一个简单的装饰器就可以了。
public String humanReadable(long size) {
long limit = 10 * 1024;
long limit2 = limit * 2 - 1;
String negative = "";
if(size < 0) {
negative = "-";
size = Math.abs(size);
}
if(size < limit) {
return String.format("%s%s bytes", negative, size);
} else {
size = Math.round((double) size / 1024);
if (size < limit2) {
return String.format("%s%s kB", negative, size);
} else {
size = Math.round((double)size / 1024);
if (size < limit2) {
return String.format("%s%s MB", negative, size);
} else {
size = Math.round((double)size / 1024);
if (size < limit2) {
return String.format("%s%s GB", negative, size);
} else {
size = Math.round((double)size / 1024);
return String.format("%s%s TB", negative, size);
}
}
}
}
}