Wenn Sie Android verwenden, können Sie einfach Android.text.format.Formatter.formatFileSize() . Der Vorteil ist, dass es einfach zu benutzen ist, und dass es vom Gebietsschema abhängt, um es für den Benutzer schön darzustellen. Der Nachteil ist, dass es nicht mit EB umgehen kann und dass es nur für die metrischen Einheiten verwendet wird (jedes Kilo ist 1000 Bytes, ohne die Möglichkeit, es als 1024 Bytes zu verwenden).
Alternativ dazu gibt es eine Lösung, die auf dieser beliebte Beitrag :
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)}")
43 Stimmen
Wenn Sie die standardisierten Einheiten verwenden, sollte 1024 zu "1KiB" und 1024*1024 zu "1MiB" werden. de.wikipedia.org/wiki/Binary_prefix
0 Stimmen
@Pascal: Es sollte mehrere Funktionen oder eine Option zur Angabe der Basis und der Einheit geben.
0 Stimmen
Mögliche Duplikate von Dateigröße als MB, GB usw. formatieren
4 Stimmen
@Pascal Cuoq: Danke für den Hinweis. Mir war nicht klar, dass wir hier in der EU gesetzlich verpflichtet sind, die richtigen Präfixe zu verwenden, bis ich ihn gelesen habe.
2 Stimmen
@DerMike Sie erwähnten, dass "bis eine solche Bibliothek existiert". Das ist jetzt wahr geworden :-) stackoverflow.com/questions/3758606/
1 Stimmen
@AaronDigulla Sie haben Recht. Warum war das 2 Monate ältere Frage als Duplikat geschlossen, und nicht dieses hier?
0 Stimmen
Ähnliches Thema in Kotlin stackoverflow.com/q/59234916
1 Stimmen
@hc_dev Ich nehme an, dass die 2 Monate ältere Frage geschlossen wurde, weil diese Frage weitaus bessere Antworten enthielt. Diese Fragen wurden beide 2010 gestellt, die andere wurde erst 2013 geschlossen. (SO sollte wirklich eine "Fragen zusammenführen"-Funktion haben, um die Antworten von beiden an einem Ort zu sammeln).