用Java解析人类可读的文件到字节

时间:2012-08-23 11:31:50

标签: java

我有一堆文件大小,我想解析。这些目前仅在GB中。以下是一些示例:

  • 1.2GB
  • 2.4GB

我认为我应该将我的字节文件大小存储在Long值中,但我似乎无法弄明白。以下是我的表现:

System.out.println(Float.parseFloat("1.2GB".replace("GB", ""))* 1024L * 1024L * 1024L);

这将返回Float值,该值显示为1.28849024E9。如何以字节为单位获取文件大小的Long表示。

我对数字数据类型感到困惑。感谢。

7 个答案:

答案 0 :(得分:9)

改为使用BigDecimal

BigDecimal bytes = new BigDecimal("1.2GB".replace("GB", ""));
bytes = bytes.multiply(BigDecimal.valueOf(1024).pow(3));
long value = bytes.longValue();

您可以将其放入方法中:

public static long toBytes(String filesize) {
    long returnValue = -1;
    Pattern patt = Pattern.compile("([\\d.]+)([GMK]B)", Pattern.CASE_INSENSITIVE);
    Matcher matcher = patt.matcher(filesize);
    Map<String, Integer> powerMap = new HashMap<String, Integer>();
    powerMap.put("GB", 3);
    powerMap.put("MB", 2);
    powerMap.put("KB", 1);
    if (matcher.find()) {
      String number = matcher.group(1);
      int pow = powerMap.get(matcher.group(2).toUpperCase());
      BigDecimal bytes = new BigDecimal(number);
      bytes = bytes.multiply(BigDecimal.valueOf(1024).pow(pow));
      returnValue = bytes.longValue();
    }
    return returnValue;
}

并称之为:

long bytes = toBytes("1.2GB");

答案 1 :(得分:7)

此功能将为您提供更通用的解决方案。它涵盖GB,MB和KB,并允许小数分隔符使用逗号和点。如果输入一个普通整数,它也会传递它。

public static long parseFilesize(String in) {
  in = in.trim();
  in = in.replaceAll(",",".");
  try { return Long.parseLong(in); } catch (NumberFormatException e) {}
  final Matcher m = Pattern.compile("([\\d.,]+)\\s*(\\w)").matcher(in);
  m.find();
  int scale = 1;
  switch (m.group(2).charAt(0)) {
      case 'G' : scale *= 1024;
      case 'M' : scale *= 1024;
      case 'K' : scale *= 1024; break;
      default: throw new IllegalArgumentException();
  }
  return Math.round(Double.parseDouble(m.group(1)) * scale);
}

答案 2 :(得分:2)

不使用BigDecimal的较短版本。

public static long parseSize(String text) {
    double d = Double.parseDouble(text.replaceAll("[GMK]B$", ""));
    long l = Math.round(d * 1024 * 1024 * 1024L);
    switch (text.charAt(Math.max(0, text.length() - 2))) {
        default:  l /= 1024;
        case 'K': l /= 1024;
        case 'M': l /= 1024;
        case 'G': return l;
    }
}

for (String s : "1.2GB 2.4GB 3.75MB 1.28KB 9".split(" "))
    System.out.println(s + " = " + parseSize(s));

打印

1.2GB = 1288490189
2.4GB = 2576980378
3.75MB = 3932160
1.28KB = 1310
9 = 9
1.2884901888E9

答案 3 :(得分:1)

如果您使用Float,则可能会失去精确度。

替代方案可能是使用BigDecimal

答案 4 :(得分:1)

这样的事情怎么样:

String sizeStr = "1.2GB";

Double base = 1024*Double.parseDouble(sizeStr.replaceAll("[GM]B",""));

final long sizeBytes;

if ( sizeStr.endsWith("GB") ) {
    sizeBytes = 1024*1024*base.longValue());
}
else {
    sizeBytes = 1024*base.longValue());
}

答案 5 :(得分:1)

如果使用groovy是一个选项,这里有一个版本:

  • 处理非后缀字符串(即只是数字“1234”)
  • 处理空格和逗号(如“12,234B”或“12 234kB”)
  • 在无法解析输入字符串
  • 时抛出一个有点描述性的异常
  • 在错误的情况下处理前缀和字节指示符。可以说这不是一个好主意。在我的特定用例中,我经常得到不精确的indata,这使得算法在规则上有点宽松是有用的。

代码:

import static groovy.test.GroovyAssert.shouldFail

long toBytes(String size) { 
  def matcher = size?.replaceAll(/[, ]/, '') =~ /(?i)^([\d.,]+)([PTGMK]?B)?$/
  if (!matcher) throw new IllegalArgumentException("Can not parse size string '${size}'")

  (matcher[0][1] as BigDecimal) * 1024**[PB:5, TB:4, GB:3, MB:2, KB:1].withDefault {0}[matcher[0][2]?.toUpperCase()]
}

assert toBytes(" 112 ")     == 112
assert toBytes("112")       == 112
assert toBytes("123456789") == 123456789
assert toBytes("1B")        == 1
assert toBytes("1KB")       == 1024
assert toBytes("300MB")     == 300g*1024*1024
assert toBytes("1.2mb")     == 1.2g*1024*1024 as Long
assert toBytes("123 456kB") == 123456g*1024
assert toBytes("123,456B")  == 123456
assert toBytes("1.5GB")     == 1.5g*1024*1024*1024  
assert toBytes("300MB")     == 300g*1024*1024
assert toBytes("512GB")     == 512g*1024*1024*1024
assert toBytes("1Tb")       == 1024g*1024*1024*1024
assert toBytes("1PB")       == 1024g*1024*1024*1024*1024

def checkFailure = { c -> 
  assert shouldFail(c).message.startsWith("Can not parse size string")
}

checkFailure { toBytes(null)   }
checkFailure { toBytes("")     } 
checkFailure { toBytes("x112") }
checkFailure { toBytes("112x") }
checkFailure { toBytes("11x2") }

该方法可能未针对可读性进行优化。尝试在保持代码简洁的同时处理所有边缘情况时有一些乐趣。

答案 6 :(得分:0)

您可以在打印之前将Float值转换为Long值。