如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
如何在Java中将字节大小转换为人类可读的格式?
比如1024应该变成“1 Kb”,1024*1024应该变成“1 Mb”。
我有点厌倦了为每个项目写这个实用方法。在Apache Commons中有这样的静态方法吗?
我最近问了同样的问题:
格式文件大小为MB, GB等。
虽然没有开箱即用的答案,但我可以接受这个解决方案:
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;
public static String convertToStringRepresentation(final long value){
final long[] dividers = new long[] { T, G, M, K, 1 };
final String[] units = new String[] { "TB", "GB", "MB", "KB", "B" };
if(value < 1)
throw new IllegalArgumentException("Invalid file size: " + value);
String result = null;
for(int i = 0; i < dividers.length; i++){
final long divider = dividers[i];
if(value >= divider){
result = format(value, divider, units[i]);
break;
}
}
return result;
}
private static String format(final long value,
final long divider,
final String unit){
final double result =
divider > 1 ? (double) value / (double) divider : (double) value;
return new DecimalFormat("#,##0.#").format(result) + " " + unit;
}
测试代码:
public static void main(final String[] args){
final long[] l = new long[] { 1l, 4343l, 43434334l, 3563543743l };
for(final long ll : l){
System.out.println(convertToStringRepresentation(ll));
}
}
输出(在我的德语地区):
1 B
4,2 KB
41,4 MB
3,3 GB
我已经打开了一个问题,要求谷歌番石榴的这个功能。也许有人愿意支持它。
有趣的事实:这里发布的原始代码片段是Stack Overflow上被复制最多的Java代码片段,它是有缺陷的。它被修好了,但却变得一团糟。 本文的完整故事:有史以来复制最多的堆栈溢出代码片段是有缺陷的!
来源:格式化字节大小到人类可读的格式|编程。指南
SI(1 k = 1,000)
public static String humanReadableByteCountSI(long bytes) {
if (-1000 < bytes && bytes < 1000) {
return bytes + " B";
}
CharacterIterator ci = new StringCharacterIterator("kMGTPE");
while (bytes <= -999_950 || bytes >= 999_950) {
bytes /= 1000;
ci.next();
}
return String.format("%.1f %cB", bytes / 1000.0, ci.current());
}
二进制(1's = 1,024)
public static String humanReadableByteCountBin(long bytes) {
long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
if (absB < 1024) {
return bytes + " B";
}
long value = absB;
CharacterIterator ci = new StringCharacterIterator("KMGTPE");
for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
value >>= 10;
ci.next();
}
value *= Long.signum(bytes);
return String.format("%.1f %ciB", value / 1024.0, ci.current());
}
示例输出:
SI BINARY
0: 0 B 0 B
27: 27 B 27 B
999: 999 B 999 B
1000: 1.0 kB 1000 B
1023: 1.0 kB 1023 B
1024: 1.0 kB 1.0 KiB
1728: 1.7 kB 1.7 KiB
110592: 110.6 kB 108.0 KiB
7077888: 7.1 MB 6.8 MiB
452984832: 453.0 MB 432.0 MiB
28991029248: 29.0 GB 27.0 GiB
1855425871872: 1.9 TB 1.7 TiB
9223372036854775807: 9.2 EB 8.0 EiB (Long.MAX_VALUE)
FileUtils。如果你的项目依赖于org.apache.commons.io, byteCountToDisplaySize(长尺寸)可以工作。
此方法的JavaDoc
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);
}
filename=filedilg.getSelectedFile().getAbsolutePath();
File file=new File(filename);
String disp=FileUtils.byteCountToDisplaySize(file.length());
System.out.println("THE FILE PATH IS "+file+"THIS File SIZE IS IN MB "+disp);
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 "???";
}
如果你使用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)}")
我们可以完全避免使用缓慢的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));
}
String[] fileSizeUnits = {"bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};
public String calculateProperFileSize(double bytes){
String sizeToReturn = "";
int index = 0;
for(index = 0; index < fileSizeUnits.length; index++){
if(bytes < 1024){
break;
}
bytes = bytes / 1024;
}
System.out.println("File size in proper format: " + bytes + " " + fileSizeUnits[index]);
sizeToReturn = String.valueOf(bytes) + " " + fileSizeUnits[index];
return sizeToReturn;
}
只需添加更多的文件单元(如果有任何缺失),你将看到单元大小达到该单元(如果你的文件有那么长):
private String bytesIntoHumanReadable(long bytes) {
long kilobyte = 1024;
long megabyte = kilobyte * 1024;
long gigabyte = megabyte * 1024;
long terabyte = gigabyte * 1024;
if ((bytes >= 0) && (bytes < kilobyte)) {
return bytes + " B";
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
return (bytes / kilobyte) + " KB";
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
return (bytes / megabyte) + " MB";
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
return (bytes / gigabyte) + " GB";
} else if (bytes >= terabyte) {
return (bytes / terabyte) + " TB";
} else {
return bytes + " Bytes";
}
}
这是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);
}
下面是上面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#项目时,这个问题/答案出现在谷歌搜索的顶部。
现在有一个包含单元格式的库可用。我把它添加到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
字节单位允许你这样做:
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);
试试JSR 363。它的单元扩展模块,如Unicode CLDR(在GitHub: uom-systems中),为您完成所有这些。
你可以使用每个实现中包含的MetricPrefix或BinaryPrefix(与上面的一些例子相比),如果你在印度或附近的国家生活和工作,IndianPrefix(也在uom-系统的公共模块中)允许你使用和格式化“千万字节”或“Lakh字节”。
创建接口:
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
你可以使用StringUtils的TraditionalBinarPrefix:
public static String humanReadableInt(long number) {
return TraditionalBinaryPrefix.long2String(number, ””, 1);
}
也许你可以使用下面的代码(在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";
这是一个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)
}
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);
}
}
}
}
}
使用下面的函数来获得确切的信息。它是基于atm_cashwithdraw概念生成的。
getFullMemoryUnit(): Total: [123 MB], Max: [1 GB, 773 MB, 512 KB], Free: [120 MB, 409 KB, 304 Bytes]
public static String getFullMemoryUnit(long unit) {
long BYTE = 1024, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
long KILO_BYTE, MEGA_BYTE = 0, GIGA_BYTE = 0, TERA_BYTE = 0;
unit = Math.abs(unit);
StringBuffer buffer = new StringBuffer();
if ( unit / TB > 0 ) {
TERA_BYTE = (int) (unit / TB);
buffer.append(TERA_BYTE+" TB");
unit -= TERA_BYTE * TB;
}
if ( unit / GB > 0 ) {
GIGA_BYTE = (int) (unit / GB);
if (TERA_BYTE != 0) buffer.append(", ");
buffer.append(GIGA_BYTE+" GB");
unit %= GB;
}
if ( unit / MB > 0 ) {
MEGA_BYTE = (int) (unit / MB);
if (GIGA_BYTE != 0) buffer.append(", ");
buffer.append(MEGA_BYTE+" MB");
unit %= MB;
}
if ( unit / KB > 0 ) {
KILO_BYTE = (int) (unit / KB);
if (MEGA_BYTE != 0) buffer.append(", ");
buffer.append(KILO_BYTE+" KB");
unit %= KB;
}
if ( unit > 0 ) buffer.append(", "+unit+" Bytes");
return buffer.toString();
}
我刚刚修改了facebookarchive-StringUtils的代码以获得以下格式。与使用apache.hadoop-StringUtils时得到的格式相同
getMemoryUnit(): Total: [123.0 MB], Max: [1.8 GB], Free: [120.4 MB]
public static String getMemoryUnit(long bytes) {
DecimalFormat oneDecimal = new DecimalFormat("0.0");
float BYTE = 1024.0f, KB = BYTE, MB = KB * KB, GB = MB * KB, TB = GB * KB;
long absNumber = Math.abs(bytes);
double result = bytes;
String suffix = " Bytes";
if (absNumber < MB) {
result = bytes / KB;
suffix = " KB";
} else if (absNumber < GB) {
result = bytes / MB;
suffix = " MB";
} else if (absNumber < TB) {
result = bytes / GB;
suffix = " GB";
}
return oneDecimal.format(result) + suffix;
}
以上方法的使用示例:
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
int availableProcessors = runtime.availableProcessors();
long heapSize = Runtime.getRuntime().totalMemory();
long heapMaxSize = Runtime.getRuntime().maxMemory();
long heapFreeSize = Runtime.getRuntime().freeMemory();
System.out.format("Total: [%s], Max: [%s], Free: [%s]\n", heapSize, heapMaxSize, heapFreeSize);
System.out.format("getMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
getMemoryUnit(heapSize), getMemoryUnit(heapMaxSize), getMemoryUnit(heapFreeSize));
System.out.format("getFullMemoryUnit(): Total: [%s], Max: [%s], Free: [%s]\n",
getFullMemoryUnit(heapSize), getFullMemoryUnit(heapMaxSize), getFullMemoryUnit(heapFreeSize));
}
字节来获取上面的格式
Total: [128974848], Max: [1884815360], Free: [126248240]
为了以人类可读的格式显示时间,请使用函数millisToShortDHMS(长持续时间)。
下面是从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)
}
}
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 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);
}
}
我使用了一个比公认答案稍作修改的方法:
public static String formatFileSize(long bytes) {
if (bytes <= 0)
return "";
if (bytes < 1000)
return bytes + " B";
CharacterIterator ci = new StringCharacterIterator("kMGTPE");
while (bytes >= 99_999) {
bytes /= 1000;
ci.next();
}
return String.format(Locale.getDefault(), "%.1f %cB", bytes / 1000.0, ci.current());
}
因为我想看到另一个输出:
SI
0: <--------- instead of 0 B
27: 27 B
999: 999 B
1000: 1.0 kB
1023: 1.0 kB
1024: 1.0 kB
1728: 1.7 kB
110592: 0.1 MB <--------- instead of 110.6 kB
7077888: 7.1 MB
452984832: 0.5 GB <--------- instead of 453.0 MB
28991029248: 29.0 GB
下面是一个快速,简单和可读的代码片段来实现这一点:
/**
* 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等) 上面的代码是快速的,使用非常少的内存。基于在我个人的入门级云计算机上运行的基准测试,它是最快的(在这些情况下性能并不重要,但仍然如此) 以上代码是一个很好的答案的修改版本
这是另一个简洁的解决方案,没有循环,但具有区域敏感格式和正确的二进制前缀:
import java.util.Locale;
public final class Bytes {
private Bytes() {
}
public static String format(long value, Locale locale) {
if (value < 1024) {
return value + " B";
}
int z = (63 - Long.numberOfLeadingZeros(value)) / 10;
return String.format(locale, "%.1f %siB", (double) value / (1L << (z * 10)), " KMGTPE".charAt(z));
}
}
测试:
Locale locale = Locale.getDefault()
System.out.println(Bytes.format(1L, locale))
System.out.println(Bytes.format(2L * 1024, locale))
System.out.println(Bytes.format(3L * 1024 * 1024, locale))
System.out.println(Bytes.format(4L * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(5L * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(6L * 1024 * 1024 * 1024 * 1024 * 1024, locale))
System.out.println(Bytes.format(Long.MAX_VALUE, locale))
输出:
1 B
2.0 KiB
3.0 MiB
4.0 GiB
5.0 GiB
6.0 PiB
8.0 EiB
Kotlin爱好者可以使用这个扩展:
fun Long.readableFormat(): String {
if (this <= 0 ) return "0"
val units = arrayOf("B", "kB", "MB", "GB", "TB")
val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
}
现在使用
val size : Long = 90836457
val readbleString = size.readableFormat()
另一种方法
val Long.formatSize : String
get() {
if (this <= 0) return "0"
val units = arrayOf("B", "kB", "MB", "GB", "TB")
val digitGroups = (log10(this.toDouble()) / log10(1024.0)).toInt()
return DecimalFormat("#,##0.#").format(this / 1024.0.pow(digitGroups.toDouble())).toString() + " " + units[digitGroups]
}
现在使用
val size : Long = 90836457
val readbleString = size.formatSize
实际上,兆字节已经足够人类阅读了。
long l = 1367343104l;
String s = String.format("%dm", l / 1024 / 1024);
1304米
如果在Android上,你可以简单地调用Android .text. format . formatter的一个静态方法。
https://developer.android.com/reference/android/text/format/Formatter