字符串输出文件的大小,输出文件大小.(java内置numberOfLeadingZeros)

又是发现了项目中的一个工具方法 , 因为数据库里面存的直接就是一个bigint数据,也就是文件的Byte大小,返回给前端展示的时候需要处理到最大单位,然后保留小数 , 给他优化了一下写法 (原来的写法是用/1024这么搞的)

涉及到2的指数真的是非常好的一个东西 , 可以方便的用位运算 , 或者直接调用内置位运算方法
这里因为是1024一个进位 , 所以正好是10个bit位 , long是64bit , 所以最多其实表示的是 EB级别的
首先把60个bit位给他进位掉 , long是带符号的 , 再剩下就是3个bit也就是7 , 因为后面也都是1 , 最大值就是8EB少个byte
文件大小的进位是这样的 : “B”, “KB”, “MB”, “GB”, “TB”, “PB”, “EB”, “ZB”, “YB” , 这里ZB和YB用不着了, 不过留着也没事

虽然之前那个老方法里面一直 /1024 和 % 1024也不是不能用 (说起来/1024是可以优化为 << 10的,性能更好,但是实际几次计算而已,耗时忽略不计) ,所以虽然改了方法 , 但是性能貌似没有变快 , 主要还是 BigDecimal 的锅,bigDecimal除法比起直接计算肯定慢 . 然后BigDecimal也不知道是除法慢还是toString的时候慢 ,

  • 然后第一版小优化 bigDecimal , 不过大差不差,
  • 然后试了试自己做除法和做小数点 , 能挽回点性能,但是代码又变冗余了 , 没有一个两行代码简洁(外加一个辅助的数组)

代码

方法一和方法二

	// ============================== 方法1
    static String[] tails = {"B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"};

    public static String getPrintSize_bigDecimal(long size) {
        int i = (63 - Long.numberOfLeadingZeros(size)) / 10;
        return BigDecimal.valueOf(size).divide(BigDecimal.valueOf(1L << (i * 10)), 2, RoundingMode.HALF_UP) + tails[i];
    }

    static BigDecimal[] numbers = new BigDecimal[]{BigDecimal.ONE, BigDecimal.valueOf(1L << 10), BigDecimal.valueOf(1L << 20),
            BigDecimal.valueOf(1L << 30), BigDecimal.valueOf(1L << 40), BigDecimal.valueOf(1L << 50), BigDecimal.valueOf(1L << 60)};

    public static String getPrintSize_bigDecimal_v2(long size) {
        int i = (63 - Long.numberOfLeadingZeros(size)) / 10;
        return BigDecimal.valueOf(size).divide(numbers[i], 2, RoundingMode.HALF_UP) + tails[i];
    }    

方法三


    static char[] unit = new char[]{' ', 'K', 'M', 'G', 'T', 'P', 'E'};
    public static String getPrintSize(long size) {
        if (size < 1024) {
            return size + ".00B";
        }
        int i = (63 - Long.numberOfLeadingZeros(size)) / 10;
        long base = 1L << (i * 10);
        char[] resItem = new char[]{'0', '0', '0', '0', '.', '0', '0', ' ', 'B'};// . 是 4 ,
        resItem[7] = unit[i];
        long leftPart = size / base;
        int start;
        for (start = 3; leftPart > 0; start--) {
            resItem[start] = (char) (leftPart % 10 + '0');
            leftPart /= 10;
        }
//        long rightPart = (size * 100 / base) % 100; // 不四舍五入 , 直接舍弃第三位小数
        long rightPart = ((size * 1000 / base) + 5) / 10 % 100;  //  这个是四舍五入的
        for (int rightStart = 6; rightPart > 0; rightStart--) {
            resItem[rightStart] = (char) (rightPart % 10 + '0');
            rightPart /= 10;
        }
        return new String(resItem, start + 1, 8 - start);
    }

前置了解

如果看过这个 numberOfLeadingZeros 方法可以跳过
特殊处理部分 : 负数的首个bit是-1,所以直接返回32 , 0的话纯0 , 所以是32
正数部分 : 简单二分法思想来找到首位1的位置,刚开始的步长是int的bit位数(32)的一半16,利用和2的指数比来确定首位1的位置 . 如果在左侧 , 前置0数量-16 , 右移16位计算,右侧变成原来的前16位,步长变为8,一直重复.


    public static int numberOfLeadingZeros(int i) {
        // HD, Count leading 0's
        if (i <= 0)
            return i == 0 ? 32 : 0;
        int n = 31;
        if (i >= 1 << 16) { n -= 16; i >>>= 16; }
        if (i >= 1 <<  8) { n -=  8; i >>>=  8; }
        if (i >= 1 <<  4) { n -=  4; i >>>=  4; }
        if (i >= 1 <<  2) { n -=  2; i >>>=  2; }
        return n - (i >>> 1);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值