问题
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:
define method
Number parse(String arg0)
as static due to it utility naturedefine
factor
s for each type of size definition asfinal 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 not1.6GB
) - Does not support spaces (so, you can use
1GB
but not1 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