Java - Convert Human Readable Size to Bytes

僤鯓⒐⒋嵵緔 提交于 2019-11-28 03:19:28

问题


I've found lots of information about converting raw byte information into a human-readable format, but I need to do the opposite, i.e. convert the String "1.6 GB" into the long value 1717990000. Is there an in-built/well-defined way to do this, or will I pretty much have to roll my own?

[Edit]: Here is my first stab...

static class ByteFormat extends NumberFormat {
    @Override
    public StringBuffer format(double arg0, StringBuffer arg1, FieldPosition arg2) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public StringBuffer format(long arg0, StringBuffer arg1, FieldPosition arg2) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Number parse(String arg0, ParsePosition arg1) {
        return parse (arg0);
    }

    @Override
    public Number parse(String arg0) {
        int spaceNdx = arg0.indexOf(" ");
        double ret = Double.parseDouble(arg0.substring(0, spaceNdx));
        String unit = arg0.substring(spaceNdx + 1);
        int factor = 0;
        if (unit.equals("GB")) {
            factor = 1073741824;
        }
        else if (unit.equals("MB")) {
            factor = 1048576;
        }
        else if (unit.equals("KB")) {
            factor = 1024;
        }

        return ret * factor;
    }
}

回答1:


I've never heard about such well-known library, which implements such text-parsing utility methods. But your solution seems to be near from correct implementation.

The only two things, which I'd like to correct in your code are:

  1. define method Number parse(String arg0) as static due to it utility nature

  2. define factors for each type of size definition as final static fields.

I.e. it will be like this one:

private final static long KB_FACTOR = 1024;
private final static long MB_FACTOR = 1024 * KB_FACTOR;
private final static long GB_FACTOR = 1024 * MB_FACTOR;

public static double parse(String arg0) {
    int spaceNdx = arg0.indexOf(" ");
    double ret = Double.parseDouble(arg0.substring(0, spaceNdx));
    switch (arg0.substring(spaceNdx + 1)) {
        case "GB":
            return ret * GB_FACTOR;
        case "MB":
            return ret * MB_FACTOR;
        case "KB":
            return ret * KB_FACTOR;
    }
    return -1;
}



回答2:


A revised version of Andremoniy's answer that properly distinguishes between kilo and kibi, etc.

private final static long KB_FACTOR = 1000;
private final static long KIB_FACTOR = 1024;
private final static long MB_FACTOR = 1000 * KB_FACTOR;
private final static long MIB_FACTOR = 1024 * KIB_FACTOR;
private final static long GB_FACTOR = 1000 * MB_FACTOR;
private final static long GIB_FACTOR = 1024 * MIB_FACTOR;

public static double parse(String arg0) {
    int spaceNdx = arg0.indexOf(" ");
    double ret = Double.parseDouble(arg0.substring(0, spaceNdx));
    switch (arg0.substring(spaceNdx + 1)) {
        case "GB":
            return ret * GB_FACTOR;
        case "GiB":
            return ret * GIB_FACTOR;
        case "MB":
            return ret * MB_FACTOR;
        case "MiB":
            return ret * MIB_FACTOR;
        case "KB":
            return ret * KB_FACTOR;
        case "KiB":
            return ret * KIB_FACTOR;
    }
    return -1;
}



回答3:


All in one answer, parses to long:

public class SizeUtil {

    public static String units = "BKMGTPEZY";

    public static long parse(String arg0) {
        int spaceNdx = arg0.indexOf(" ");    
        double ret = Double.parseDouble(arg0.substring(0, spaceNdx));
        String unitString = arg0.substring(spaceNdx+1);
        int unitChar = unitString.charAt(0);
        int power = units.indexOf(unitChar);
        boolean isSi = unitString.indexOf('i')!=-1;
        int factor = 1024;
        if (isSi) 
        {
            factor = 1000;
        }

        return new Double(ret * Math.pow(factor, power)).longValue();
    }

    public static void main(String[] args) {
        System.out.println(parse("300.00 GiB")); // requires a space
        System.out.println(parse("300.00 GB"));
        System.out.println(parse("300.00 B"));
        System.out.println(parse("300 EB"));
    }
}



回答4:


Spring Framework, on version 5.1, added a DataSize class which allows parsing human-readable data sizes into bytes, and also formatting them back to their human-readable form. It can be found here.

If you use Spring Framework, you can upgrade to >=5.1 and use this class. Otherwise you can c/p it and the related classes (while complying to the license).

Then you can use it:

DataSize dataSize = DataSize.parse("16GB");
System.out.println(dataSize.toBytes());

will give the output:

17179869184

However, the pattern used to parse your input

  • Does not support decimals (so, you can use 1GB, 2GB, 1638MB, but not 1.6GB)
  • Does not support spaces (so, you can use 1GB but not 1 GB)

I would recommend to stick to the convention for compatibility/easy maintainability. But if that does not suit your needs, you need to copy & edit the file - it is a good place to start.




回答5:


I know this is much later but I was looking for a similar function which takes into account the SI prefix as well. So I landed up creating one myself and I thought it might be useful for other people.

public static String units = "KMGTPE";

/**
 * Converts from human readable to byte format
 * @param number The number value of the amount to convert
 * @param unit The unit: B, KB, MB, GB, TB, PB, EB
 * @param si Si prefix
 * @return byte value
 */
public static double parse(double number, String unit, boolean si)
{
    String identifier = unit.substring(0, 1);
    int index = units.indexOf(identifier);
    //not already in bytes
    if (index!=-1)
    {
        for (int i = 0; i <= index; i++)
            number = number * (si ? 1000 : 1024);
    }
    return number;
}

I'm sure this is possible to do with recursion as well. It was too simple to bother...




回答6:


Following approach can also be used and makes it generic, and not dependent on space character to parse.

Thanks to @RobAu for the hint above. Added a new method to get the index of first letter in the string, and changed the parse method to get index based on this new method. I have kept the original parse method and added a new parseAny method, so the results can be compared. Hope it helps someone.

Also, thanks to this answer for the indexOf method - https://stackoverflow.com/a/11214786/6385674.

public class ConversionUtil {

    public static String units = "BKMGTPEZY";

    public static long parse(String arg0) {
        int spaceNdx = arg0.indexOf(" ");    
        double ret = Double.parseDouble(arg0.substring(0, spaceNdx));
        String unitString = arg0.substring(spaceNdx+1);
        int unitChar = unitString.charAt(0);
        int power = units.indexOf(unitChar);
        boolean isSi = unitString.indexOf('i')!=-1;
        int factor = 1024;
        if (isSi) 
        {
            factor = 1000;
        }

        return new Double(ret * Math.pow(factor, power)).longValue();
    }
    /** @return index of pattern in s or -1, if not found */
    public static int indexOf(Pattern pattern, String s) {
        Matcher matcher = pattern.matcher(s);
        return matcher.find() ? matcher.start() : -1;
    }    
    public static long parseAny(String arg0)
    {
        int index = indexOf(Pattern.compile("[A-Za-z]"), arg0);
        double ret = Double.parseDouble(arg0.substring(0, index));
        String unitString = arg0.substring(index);
        int unitChar = unitString.charAt(0);
        int power = units.indexOf(unitChar);
        boolean isSi = unitString.indexOf('i')!=-1;
        int factor = 1024;
        if (isSi) 
        {
            factor = 1000;
        }

        return new Double(ret * Math.pow(factor, power)).longValue();       

    }
    public static void main(String[] args) {
        System.out.println(parse("300.00 GiB")); // requires a space
        System.out.println(parse("300.00 GB"));
        System.out.println(parse("300.00 B"));        
        System.out.println(parse("300 EB"));
        System.out.println(parseAny("300.00 GiB"));
        System.out.println(parseAny("300M"));
    }
}


来源:https://stackoverflow.com/questions/16968587/java-convert-human-readable-size-to-bytes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!