Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ByteCountFormatter iOS Swift

Convert Bytes values into GB/MB/KB, i am using ByteCountFormatter. Example code below.

func converByteToGB(_ bytes:Int64) -> String {
        let formatter:ByteCountFormatter = ByteCountFormatter()
        formatter.countStyle = .binary

        return formatter.string(fromByteCount: Int64(bytes))
    }

Now, my requirement is it should show only one digit after decimal point. Example for 1.24 GB => 1.2 GB, not like 1.24 GB. force it for single digit after apply floor or ceil function.

like image 680
Sheshnath Avatar asked May 05 '17 10:05

Sheshnath


1 Answers

ByteCountFormatter is not capable to show only one digit after decimal point. It shows by default 0 fraction digits for bytes and KB; 1 fraction digits for MB; 2 for GB and above. If isAdaptive is set to false it tries to show at least three significant digits, introducing fraction digits as necessary.

ByteCountFormatter also trims trailing zeros. To disable set zeroPadsFractionDigits to true.

I have adapted How to convert byte size into human readable format in java? to do what you want:

func humanReadableByteCount(bytes: Int) -> String {
    if (bytes < 1000) { return "\(bytes) B" }
    let exp = Int(log2(Double(bytes)) / log2(1000.0))
    let unit = ["KB", "MB", "GB", "TB", "PB", "EB"][exp - 1]
    let number = Double(bytes) / pow(1000, Double(exp))
    return String(format: "%.1f %@", number, unit)
}

Notice this will format KB and MB differently than ByteCountFormatter. Here is a modification that removes trailing zero and does not show fraction digits for KB and for numbers larger than 100.

func humanReadableByteCount(bytes: Int) -> String {
    if (bytes < 1000) { return "\(bytes) B" }
    let exp = Int(log2(Double(bytes)) / log2(1000.0))
    let unit = ["KB", "MB", "GB", "TB", "PB", "EB"][exp - 1]
    let number = Double(bytes) / pow(1000, Double(exp))
    if exp <= 1 || number >= 100 {
        return String(format: "%.0f %@", number, unit)
    } else {
        return String(format: "%.1f %@", number, unit)
            .replacingOccurrences(of: ".0", with: "")
    }
}

Be also aware that this implementation does not take Locale into account. For example some locales use comma (",") instead of dot (".") as decimal separator.

like image 162
Marián Černý Avatar answered Oct 17 '22 11:10

Marián Černý