4

我有一堆要解析的文件大小。这些目前仅以 GB 为单位。以下是一些示例:

  • 1.2GB
  • 2.4GB

我想我应该将我的字节文件大小存储在一个Long值中,但我似乎无法弄清楚。这是我的做法:

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

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

我对数字数据类型有点困惑。谢谢。

4

7 回答 7

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");
于 2012-08-23T11:34:03.467 回答
8

此功能将为您提供更通用的解决方案。它涵盖 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);
}
于 2012-08-23T11:45:46.557 回答
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
于 2012-08-23T13:08:06.733 回答
1

如果你使用Float,你有失去精确度的风险。

另一种方法是使用BigDecimal.

于 2012-08-23T11:34:54.623 回答
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());
}
于 2012-08-23T11:45:42.237 回答
1

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

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

代码:

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") }

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

于 2015-10-15T11:52:01.227 回答
0

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

于 2012-08-23T11:34:39.220 回答