【发布时间】:2018-02-09 08:33:01
【问题描述】:
我想在 Apache-POI(XSSF 和 SAX 事件 API)的帮助下导入 XLSX 文件。
因为 Excel 将数字存储为浮点数,所以在 java 中需要将它们格式化为它们在 Excel 中的原始格式。这可以通过读取单元格格式来实现:
String cellStyle = sheetReader.getAttributeValue(null, "s");
if (cellStyle != null) {
// save the format of the cell for later use.
int styleIndex = Integer.parseInt(cellStyle);
XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
formatIndex = style.getDataFormat();
formatString = style.getDataFormatString();
if (formatString == null) {
// formatString could not be found, so it must be a builtin format.
formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
}
}
...
// format the floating-point value
String xlsxValue = formatter.formatRawCellContents(
Double.parseDouble(value),
formatIndex,
formatString);
上面的代码对我来说效果很好......但它给我的数字就像它们在德国语言环境中运行 Excel 时最初在 Excel 中格式化一样。此类数字的示例:
10,30
100.00.00,43
现在我要如何重新格式化这些数字,以便将它们提供给 Java Double 和 Java BigDecimal?
Apache-POI 貌似没有提供针对这种情况的 Utility-Classes,但是如何在 java 中处理这些数字呢?
我已经侵入了 poi 以使这种情况发生,但是没有其他方法吗?
// hack apache-poi classes that are private, so we can retrieve the 'format'
// which helps us to transform the formated value to the expected java-format
CellStyle style = new CellStyleHack(formatIndex, formatString);
Cell cell = new CellHack(Double.parseDouble(xlsxValue), style);
java.text.Format format = formatter.createFormat(cell);
if (format instanceof DecimalFormat) {
DecimalFormat decimalFormat = ((DecimalFormat) format);
char dSep = decimalFormat.getDecimalFormatSymbols().getDecimalSeparator();
char gSep = decimalFormat.getDecimalFormatSymbols().getGroupingSeparator();
String cSymbol = decimalFormat.getDecimalFormatSymbols().getCurrencySymbol();
// java always expects '.' as decimal seperator for BigDecimal and Double.
xlsxValue = xlsxValue.replace("" + gSep, "");
xlsxValue = xlsxValue.replace(dSep, '.');
if (cSymbol != null) {
xlsxValue = xlsxValue.replace(cSymbol, "").trim();
}
}
【问题讨论】:
-
考虑到浮点问题,我只想使用双打。但是您可以做的是获取双精度值,然后执行与 Excel 相同的操作,使用 BigDecimal.round 舍入到 15 个有效数字。我在这里展示了这个:stackoverflow.com/questions/41067328/….
-
@AxelRichter 是的,我可以这样做,谢谢指出。问题是我们的软件中有一个约定,即我们的 BigDecimals 在小数和最大值之前需要最多 9 位数字。小数后 7 位,因此它们可以存储在数据库中,我们可以确保它们不大于我们的数据库字段允许的大小。 Excel 的值例如是:62.474099999999993,大于我们的小数后 7 位。我不想切断其余的数字,我也不想失去价格价值的精确度。我上面的代码示例(这是一个 hack)没有这个问题。
-
目前无法测试。但是你可以尝试使用DataFormatter(java.util.Locale locale) 和
Locale.US吗?或者在使用DataFormatter之前将LocaleUtil.setUserLocale设置为Locale.US? -
@AxelRichter 好主意。我已经尝试过如下:
formatter = new DataFormatter(Locale.US)。我尝试使用formatRawCellContents--> 值:“1333”,格式字符串:“#,##0”结果:“1,333”。值:“1”,格式字符串:“0.00”,结果:“1.00”。所以它确实改变了一些东西,但它仍然产生“,”的结果。但谢谢这有帮助。如果使用 Locale.US 它永远不会产生逗号,这将是一个解决方案。 -
@AxelRichter 嘿,现在我想起来了。如果结果现在始终符合 Locale.US,它将始终具有“。”作为小数分隔符。酷谢谢。我认为这可以解决我的问题
标签: java excel apache-poi