存储单位转换工具类

网上找了好久没找到合适的存储单位转换工具类,自己手写了一个转换工具类(大佬勿喷),分享出来,main是使用案例,可做参考!

package com.glory.myselfdemo.utils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author ***
 */
public class StorageUnitUtil {
    /**
     * bit、B、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB、CB……
     */
    enum Unit{
        // 值必须由小到大递增
        bit,
        B,
        KB,
        MB,
        GB,
        TB,
        PB,
        EB,
        ZB,
        YB,
        BB,
        NB,
        DB,
        CB
    }

    /**
     * 换算基数:例: 1024;1000...
     */
    private final static int basic = 1024;

    /**
     * 自动转换:value>=basic,自动向大单位转换,否则返回value
     * @param value 转换前的值(不能为'0'且小于Double.MAX_VALUE)
     * @param currentUnit 转换前的单位
     * @return 返回转后的值和单位字符
     */
    public static String autoConvert(Number value, Unit currentUnit) {
        if (value.doubleValue() == 0 && value.doubleValue() < Double.MAX_VALUE) {
            throw new IllegalArgumentException("需要转换的值不能为0且小于Double.MAX_VALUE");
        }
        return autoToBig(value, currentUnit, null, null);
    }

    /**
     * 自动转换:value>=basic,自动向大单位转换,否则返回value;可定义分隔符或单位后缀
     * @param value 转换前的值(不能为'0'且小于Double.MAX_VALUE)
     * @param currentUnit 转换前的单位
     * @param separatorChar 值和单位中间的分隔符
     * @param unitSuffix 单位后面的后缀
     * @return 返回转后的值和(分隔符<若有>)单位(后缀<若有>)字符
     */
    public static String autoConvert(Number value, Unit currentUnit, String separatorChar, String unitSuffix) {
        if (value.doubleValue() == 0 && value.doubleValue() < Double.MAX_VALUE) {
            throw new IllegalArgumentException("需要转换的值不能为0且小于Double.MAX_VALUE");
        }
        return autoToBig(value, currentUnit, separatorChar, unitSuffix);
    }

    /**
     * 自动转换:valueUnit中的value>=basic,自动向大单位转换,否则返回value
     * @param valueUnit 转换前的值和单位字符
     * @return 返回转后的值和单位字符
     */
    public static String autoConvert(String valueUnit) {
        Map<String, String> map = extractArgument(valueUnit);
        if (map.isEmpty()) {
            throw new IllegalArgumentException("参数无法解析: " + valueUnit);
        } else {
            Number number = Double.valueOf(map.get("number"));
            if (number.doubleValue() == 0 && number.doubleValue() < Double.MAX_VALUE) {
                throw new IllegalArgumentException("需要转换的值不能为0");
            }
            Unit fromUnit = Unit.valueOf(map.get("unit"));
            return autoToBig(number, fromUnit, null, null);
        }
    }

    /**
     * 自动转换:valueUnit中的value>=basic,自动向大单位转换,否则返回value;可定义分隔符或单位后缀
     * @param valueUnit 转换前的值和单位字符
     * @param separatorChar 值和单位中间的分隔符
     * @param unitSuffix 单位后面的后缀
     * @return 返回转后的值和(分隔符<若有>)单位(后缀<若有>)字符
     */
    public static String autoConvert(String valueUnit, String separatorChar, String unitSuffix) {
        Map<String, String> map = extractArgument(valueUnit);
        if (map.isEmpty()) {
            throw new IllegalArgumentException("参数无法解析: " + valueUnit);
        } else {
            Number number = Double.valueOf(map.get("number"));
            if (number.doubleValue() == 0 && number.doubleValue() < Double.MAX_VALUE) {
                throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
            }
            Unit fromUnit = Unit.valueOf(map.get("unit"));
            return autoToBig(number, fromUnit, separatorChar, unitSuffix);
        }
    }

    /**
     * 指定转换:指定转换后的单位,valueUnit中的value向指定单位换算成对应的值
     * @param valueUnit 转换前的值和单位字符
     * @param toUnit 转换后的单位
     * @return 返回转后的值和单位字符
     */
    public static String customConvert(String valueUnit, Unit toUnit) {
        Map<String, String> map = extractArgument(valueUnit);
        String result;
        if (map.isEmpty()) {
            throw new IllegalArgumentException("参数无法解析: " + valueUnit);
        } else {
            Number number = Double.valueOf(map.get("number"));
            if (number.doubleValue() == 0 && number.doubleValue() < Double.MAX_VALUE) {
                throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
            }
            Unit fromUnit = Unit.valueOf(map.get("unit"));
            int fromOrdinal = fromUnit.ordinal();
            int toOrdinal = toUnit.ordinal();
            if (fromOrdinal == toOrdinal) {
                throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
            }
            // big to small
            if (fromOrdinal > toOrdinal) {
                result = customToSmall(number, fromUnit, toUnit, null, null);
            } else {
                result = autoToBig(number, fromUnit, null, null);
            }
        }
        return result;
    }

    /**
     * 指定转换:指定转换后的单位,valueUnit中的value向指定单位换算成对应的值;可定义分隔符或单位后缀
     * @param valueUnit 转换前的值和单位字符
     * @param toUnit    转换后的单位
     * @param separatorChar 值和单位中间的分隔符
     * @param unitSuffix 单位后面的后缀
     * @return 返回转后的值和(分隔符<若有>)单位(后缀<若有>)字符
     */
    public static String customConvert(String valueUnit, Unit toUnit, String separatorChar, String unitSuffix) {
        Map<String, String> map = extractArgument(valueUnit);
        String result;
        if (map.isEmpty()) {
            throw new IllegalArgumentException("参数无法解析: " + valueUnit);
        } else {
            Number number = Double.valueOf(map.get("number"));
            if (number.doubleValue() == 0 && number.doubleValue() < Double.MAX_VALUE) {
                throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
            }
            Unit fromUnit = Unit.valueOf(map.get("unit"));
            int fromOrdinal = fromUnit.ordinal();
            int toOrdinal = toUnit.ordinal();
            if (fromOrdinal == toOrdinal) {
                throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
            }
            // big to small
            if (fromOrdinal > toOrdinal) {
                result = customToSmall(number, fromUnit, toUnit, separatorChar, unitSuffix);
            } else {
                result = autoToBig(number, fromUnit, separatorChar, unitSuffix);
            }
        }
        return result;
    }

    /**
     * 指定转换:指定转换后的单位,value向指定单位换算成对应的值
     * @param value 转换前的值
     * @param currentUnit 转换前的单位
     * @param toUnit 转换后的单位
     * @return 返回转后的值和单位字符
     */
    public static String customConvert(Number value,Unit currentUnit, Unit toUnit) {
        String result;
        if (value.doubleValue() == 0 && value.doubleValue() < Double.MAX_VALUE) {
            throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
        }
        int fromOrdinal = currentUnit.ordinal();
        int toOrdinal = toUnit.ordinal();
        if (fromOrdinal == toOrdinal) {
            throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
        }
        // big to small
        if (fromOrdinal > toOrdinal) {
            result = customToSmall(value, currentUnit, toUnit, null, null);
        } else {
            result = autoToBig(value, currentUnit, null, null);
        }
        return result;
    }

    /**
     *
     * 指定转换:指定转换后的单位,value向指定单位换算成对应的值;可定义分隔符或单位后缀
     * @param value 转换前的值
     * @param currentUnit 转换前的单位
     * @param toUnit 转换后的单位
     * @param separatorChar 值和单位中间的分隔符
     * @param unitSuffix 单位后面的后缀
     * @return 返回转换后的值和(分隔符<若有>)单位(后缀<若有>)字符
     */
    public static String customConvert(Number value, Unit currentUnit, Unit toUnit, String separatorChar, String unitSuffix) {
        String result;
        if (value.doubleValue() == 0 && value.doubleValue() < Double.MAX_VALUE) {
            throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
        }
        int fromOrdinal = currentUnit.ordinal();
        int toOrdinal = toUnit.ordinal();
        if (fromOrdinal == toOrdinal) {
            throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
        }
        // big to small
        if (fromOrdinal > toOrdinal) {
            result = customToSmall(value, currentUnit, toUnit, separatorChar, unitSuffix);
        } else {
            result = autoToBig(value, currentUnit, separatorChar, unitSuffix);
        }
        return result;
    }

    /**
     * 指定转换:指定转换后的单位,value向指定单位换算成对应的值并返回
     * @param value 转换前的值
     * @param currentUnit 转换前的单位
     * @param toUnit 转换后的单位
     * @return 返回转换后的值 java.lang.Number
     */
    public static Number getNumberConvert(Number value,Unit currentUnit, Unit toUnit) {
        Number number;
        if (value.doubleValue() == 0 && value.doubleValue() < Double.MAX_VALUE) {
            throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
        }
        int fromOrdinal = currentUnit.ordinal();
        int toOrdinal = toUnit.ordinal();
        if (fromOrdinal == toOrdinal) {
            throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
        }
        // big to small
        if (fromOrdinal > toOrdinal) {
            number = customToSmall(value, currentUnit, toUnit);
        } else {
            number = autoToBig(value, currentUnit);
        }
        return number;
    }

    /**
     * 指定转换:指定转换后的单位,valueUnit中的value向指定单位换算成对应的值并返回
     * @param valueUnit 转换前的值和单位字符
     * @param toUnit 转换后的单位
     * @return 返回转换后的值 java.lang.Number
     */
    public static Number getNumberConvert(String valueUnit, Unit toUnit) {
        Map<String, String> map = extractArgument(valueUnit);
        Number number;
        if (map.isEmpty()) {
            throw new IllegalArgumentException("参数无法解析: " + valueUnit);
        } else {
            number = Double.valueOf(map.get("number"));
            if (number.doubleValue() == 0 && number.doubleValue() < Double.MAX_VALUE) {
                throw new IllegalArgumentException("需要转换的值不能为0或超出计算范围");
            }
            Unit fromUnit = Unit.valueOf(map.get("unit"));
            int fromOrdinal = fromUnit.ordinal();
            int toOrdinal = toUnit.ordinal();
            if (fromOrdinal == toOrdinal) {
                throw new IllegalArgumentException("当前单位和转换结果的目标单位不能相同");
            }
            // big to small
            if (fromOrdinal > toOrdinal) {
                number = customToSmall(number, fromUnit, toUnit);
            } else {
                number = autoToBig(number, fromUnit);
            }
        }
        return number;
    }

    private static Number customToSmall(Number number, Unit fromUnit, Unit toUnit){
        final int enumIdx = 0;
        final int special = 8;
        final int resultScale = 2;
        int fromOrdinal = fromUnit.ordinal();
        int toOrdinal = toUnit.ordinal();
        int level = fromOrdinal - toOrdinal;
        BigDecimal value = BigDecimal.valueOf(number.doubleValue());
        BigDecimal basicDec = BigDecimal.valueOf(basic);
        BigDecimal specialDec = BigDecimal.valueOf(special);
        if (toOrdinal == enumIdx) {
            level -= 1;
            value = value.multiply(specialDec);
        }
        for (int i = 1; i <= level; i++) {
            value = value.multiply(basicDec);
        }
        value = value.setScale(resultScale, RoundingMode.HALF_UP);
        return formatToLong(value);
    }

    private static String customToSmall(Number number, Unit fromUnit, Unit toUnit, String separatorChar, String unitSuffix) {
        final int enumIdx = 0;
        final int special = 8;
        final int resultScale = 2;
        int fromOrdinal = fromUnit.ordinal();
        int toOrdinal = toUnit.ordinal();
        int level = fromOrdinal - toOrdinal;
        BigDecimal value = BigDecimal.valueOf(number.doubleValue());
        BigDecimal basicDec = BigDecimal.valueOf(basic);
        BigDecimal specialDec = BigDecimal.valueOf(special);
        if (toOrdinal == enumIdx) {
            level -= 1;
            value = value.multiply(specialDec);
        }
        for (int i = 1; i <= level; i++) {
            value = value.multiply(basicDec);
        }
        value = value.setScale(resultScale, RoundingMode.HALF_UP);
        Number resultVal = formatToLong(value);
        String result = String.valueOf(resultVal);
        if (separatorChar != null && !"".equals(separatorChar) && separatorChar.length() > 0) {
            result = result.concat(separatorChar);
        }
        result = result.concat(toUnit.name());
        if (unitSuffix != null && !"".equals(unitSuffix) && unitSuffix.length() > 0) {
            result = result.concat(unitSuffix);
        }
        return result;
    }

    private static Map<String, String> extractArgument(String valUnit) {
        Map<String, String> map = new HashMap<>();
        Unit[] units = Unit.values();
//        String unitsStr = Arrays.stream(units).map(Enum::name).collect(Collectors.joining("|"));
        StringBuilder builder = new StringBuilder();
        for (Unit unit : units) {
            String name = unit.name();
            builder.append(name);
            if (unit.ordinal() < (units.length - 1)) {
                builder.append("|");
            }
        }
        final String regex = "^(\\d+[.]?\\d*)\\s*(" + builder + ")$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(valUnit);
        while (matcher.find()) {
            map.put("number", matcher.group(1));
            map.put("unit", matcher.group(2));
        }
        return map;
    }

    private static Unit getUnitByOrdinal(int ordinal) {
        Unit[] units = Unit.values();
        for (Unit unit : units) {
            if (unit.ordinal() == ordinal) {
                return unit;
            }
        }
        throw new IllegalArgumentException("未录入该存储单位");
    }

    private static Number autoToBig(Number val, Unit fromUnit) {
        final int enumIdx = 0;
        int fromOrdinal = fromUnit.ordinal();
        if (enumIdx == fromOrdinal) {
            val = bitToByte(val);
            fromOrdinal += 1;
        }
        // 计算时尽量保持精确度 保留10位小数s
        final int scale = 10;
        // 返回时保留2位小数
        final int resultScale = 2;
        BigDecimal smallVal = BigDecimal.valueOf(val.doubleValue());
        BigDecimal basicVal = BigDecimal.valueOf(basic);
        while (smallVal.compareTo(basicVal) >= 0 && (fromOrdinal < Unit.values().length - 1)) {
            smallVal = smallVal.divide(basicVal, scale, RoundingMode.HALF_UP);
            fromOrdinal += 1;
        }
        smallVal = smallVal.setScale(resultScale, RoundingMode.HALF_UP);
        return formatToLong(smallVal);
    }

    private static String autoToBig(Number val, Unit fromUnit, String separatorChar, String unitSuffix) {
        final int enumIdx = 0;
        int fromOrdinal = fromUnit.ordinal();
        if (enumIdx == fromOrdinal) {
            val = bitToByte(val);
            fromOrdinal += 1;
        }
        // 计算时尽量保持精确度 保留10位小数s
        final int scale = 10;
        // 返回时保留2位小数
        final int resultScale = 2;
        BigDecimal smallVal = BigDecimal.valueOf(val.doubleValue());
        BigDecimal basicVal = BigDecimal.valueOf(basic);
        while (smallVal.compareTo(basicVal) >= 0 && (fromOrdinal < Unit.values().length - 1)) {
            smallVal = smallVal.divide(basicVal, scale, RoundingMode.HALF_UP);
            fromOrdinal += 1;
        }
        Unit toUnit = getUnitByOrdinal(fromOrdinal);
        smallVal = smallVal.setScale(resultScale, RoundingMode.HALF_UP);
        Number number = formatToLong(smallVal);
        String result = String.valueOf(number);
        if (separatorChar != null && !"".equals(separatorChar) && separatorChar.length() > 0) {
            result = result.concat(separatorChar);
        }
        result = result.concat(toUnit.name());
        if (unitSuffix != null && !"".equals(unitSuffix) && unitSuffix.length() > 0) {
            result = result.concat(unitSuffix);
        }
        return result;
    }

    private static Number bitToByte(Number bitSize) {
        final int basic = 8;
        final int scale = 10;
        double bitDouble = bitSize.doubleValue();
        if (bitDouble == 0) {
            return bitSize;
        }
        BigDecimal bitDec = BigDecimal.valueOf(bitDouble);
        BigDecimal basicDec = BigDecimal.valueOf(basic);
        BigDecimal byteDec = bitDec.divide(basicDec, scale, RoundingMode.HALF_UP);
        return formatToLong(byteDec);
    }

    private static Number formatToLong(Number val) {
        double d = val.doubleValue();
        long l = val.longValue();
        if (d == l) {
            return l;
        }
        return val;
    }

    public static void main(String[] args) {

        String s1 = autoConvert(10240, Unit.KB);
        System.out.println("s1 = " + s1);
        //s1 = 10MB

        String s2 = autoConvert(8192, Unit.KB, " ", "/s");
        System.out.println("s2 = " + s2);
        //s2 = 8 MB/s

        String s3 = autoConvert("10240TB");
        System.out.println("s3 = " + s3);
        //s3 = 10PB

        String s4 = autoConvert("1023GB", " ", "/每天");
        System.out.println("s4 = " + s4);
        //s4 = 1023 GB/每天

        String s5 = customConvert("1TB", Unit.bit);
        System.out.println("s5 = " + s5);
        //s5 = 8796093022208bit

        String s6 = customConvert(1, Unit.TB, Unit.bit);
        System.out.println("s6 = " + s6);
        //s6 = 8796093022208bit

        String s7 = customConvert("1CB", Unit.YB);
        System.out.println("s7 = " + s7);
        //s7 = 1099511627776YB

        String s8 = autoConvert(9.8938489077261e+27,Unit.bit);
        System.out.println("s8 = " + s8);
        //s8 = 1023YB

        String s9 = customConvert(1024, Unit.B, Unit.bit, " ", null);
        System.out.println("s9 = " + s9);
        //s9 = 8192 bit

        String s10 = customConvert("1024KB", Unit.MB, " ", "/s");
        System.out.println("s10 = " + s10);
        //s10 = 1 MB/s

        Number n1 = getNumberConvert("1024GB", Unit.MB);
        System.out.println("n1 = " + n1);
        //n1 = 1048576

        Number n2 = getNumberConvert(1024, Unit.KB, Unit.MB);
        System.out.println("n2 = " + n2);
        //n2 = 1
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值