如何使用 Apache POI (SXSSF) 为特定单元格设置数据(数字)格式区域设置?

Posted

技术标签:

【中文标题】如何使用 Apache POI (SXSSF) 为特定单元格设置数据(数字)格式区域设置?【英文标题】:How to set data (number) format locale for specific cell using Apache POI (SXSSF)? 【发布时间】:2017-09-12 15:59:44 【问题描述】:

问题非常具体:使用 Apache POI,我想创建单元格(完成),为其分配数字格式(完成),并设置格式的语言环境(卡在这里)。

代码如下所示:

SXSSFWorkbook workbook = new SXSSFWorkbook(100);
Sheet sheet = workbook.createSheet();
Row row = sheet.createRow(1);
Cell cell = row.createCell(0);
CellStyle cellStyle = workbook.createCellStyle();
cellStyle.setDataFormat(8); //currency with thousands separator and two decimal places after period
cell.setCellValue(123456.78);
//??? how to set custom locale for the cell's number format?

我试图用自定义语言环境解决的问题是自定义千位分隔符字符(法语的不间断空格对我来说是可以的)。

XLSX 工作簿允许这样的自定义(更新:我的意思是为每个单元格设置格式区域设置),这可以通过 MS Office 和 OpenOffice 实现。我想在代码中做同样的事情。

(Apache POI 3.12)

【问题讨论】:

当我使用 Apache-poi 时,我不必处理语言环境,因为本地化的格式细节(例如,逗号或点)由显示数据的 Excel 确定,因此它总是正确的实际用户。这还不够吗? “XLSX 工作簿允许这样的定制”:不,它没有。对于货币数字格式,只能本地化货币符号,但不能本地化小数分隔符。这来自 Windows 系统区域设置。千位分隔符也默认为 Windows 系统区域设置。但这可以使用格式字符串进行设置。所以格式字符串可以是"#\\ ##0.00\\ [$€-40C];[RED]\\-#\\ ##0.00\\ [$€-40C]"。这是你想要的吗?但这与可用于 Libreoffice OpenDocument 电子表格格式的本地化货币格式不同。 @ZsoltV 不幸的是,这还不够。我有客户要求说“空格作为分隔符”,但我无法让客户更改计算机的区域设置 @AxelRichter XLSX 工作簿允许为特定单元格设置区域设置。不过,Apache POI 似乎没有 API。但是像“# ### ### ###”这样的格式对我有用。如果您将其发布为答案,我会接受它 "XLSX 工作簿允许为特定单元格设置区域设置。"你能告诉我怎么做吗? 【参考方案1】:

在用于货币数字格式的 Offixe OpenXML (*.xlsx) 中,只能本地化货币符号,但不能本地化小数分隔符。小数点分隔符来自运行 Excel 的 Windows 系统的 Windows 系统区域设置。千位分隔符也默认为运行 Excel 的 Windows 系统的 Windows 系统区域设置。

在 Excel 中如下所示:

如您所见,只有货币符号可以本地化。

至少可以使用格式字符串设置千位分隔符。所以格式字符串可以是

"#\\ ###\\ ##0.00\\ [$€-40C];[RED]\\-#\\ ###\\ ##0.00\\ [$€-40C]"

这是一种货币数字格式,具有本地化的法国欧元货币符号和空格作为千​​位分隔符。因为我们伪造了千位分隔符,所以我们必须在格式字符串中提供尽可能多的数字。

小数点分隔符是默认值,这意味着它来自运行 Excel 的 Windows 系统的 Windows 系统区域设置。因此,格式字符串中的点. 并不意味着始终使用点作为十进制分隔符,而是使用来自运行 Excel 的 Windows 系统的 Windows 系统区域设置的十进制分隔符。如果我们在格式字符串中使用逗号, 作为千位分隔符,这也将使用来自运行 Excel 的 Windows 系统的 Windows 系统区域设置的千位分隔符。然后我们就不需要在格式字符串中提供这么多数字了,因为这样一来,千位分隔符设置就会每千位重复一次。所以

"#,##0.00\\ [$€-40C];[RED]\\-#,##0.00\\ [$€-40C]"

足够了。

例子:

import java.io.FileOutputStream;

import org.apache.poi.ss.usermodel.*;

import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.streaming.SXSSFSheet;

public class CreateExcelNumberFormat 

 public static void main(String[] args) throws Exception 
  SXSSFWorkbook workbook = new SXSSFWorkbook(100);

  DataFormat dataformat = workbook.createDataFormat();
  CellStyle cellStyleCurrency = workbook.createCellStyle();
  cellStyleCurrency.setDataFormat(dataformat.getFormat("#\\ ###\\ ##0.00\\ [$€-40C];[RED]\\-#\\ ###\\ ##0.00\\ [$€-40C]")); 

  Sheet sheet = workbook.createSheet();
  Row row = sheet.createRow(1);
  Cell cell = row.createCell(0);

  cell.setCellValue(123456.78);
  cell.setCellStyle(cellStyleCurrency);

  ((SXSSFSheet)sheet).trackColumnForAutoSizing(0);
  sheet.autoSizeColumn(0);

  workbook.write(new FileOutputStream("CreateExcelNumberFormat.xlsx"));
  workbook.close();
  workbook.dispose();
 

但这与可用于 Libreoffice OpenDocument 电子表格格式的本地化货币格式不同。这看起来像:

正如您在此处看到的,货币符号和整个格式的语言都可以本地化。

但是Office OpenXML (*.xlsx) 无法存储本地化的货币数字格式。 OpenDocument Spreadsheet (*.ods) 是 OpenOffice/Libreoffice 的原生格式,可以保存本地化的货币数字格式,但是如果 Excel 会打开这样的文件,本地化就会丢失。

OpenOffice/Libreoffice 的“语言”组合框的设置不能存储在*.xlsx 中,也不能从 OpenOffice/Libreoffice 存储。在 OpenOffice/Libreoffice 中设置非默认值,将文件另存为 *.xlsx,关闭 OpenOffice/Libreoffice,再次在 OpenOffice/Libreoffice 中打开存储的 *.xlsx 文件。您将看到“语言”已重置为默认值。

【讨论】:

我不太明白 Excel 和 OpenOffice 的格式字符串有什么区别。只是空间被转义了吗? 我也怀疑 e。 G。 123456789 将正确显示为“123 456 789” - 而不是“123456 789”。所以完整的解决方案可能是“# ### ### ### ##0”(重复很多空格) 如果两者都保存 Office OpenXML (*.xlsx),则 Excel 和 OpenOffice/Libreoffice 的格式字符串之间没有区别。就是 Office OpenXML (*.xlsx) 无法存储本地化的货币数字格式。 OpenDocument 电子表格 (*.ods) 可以保存本地化的货币数字格式,但如果 Excel 会打开这样的文件,本地化就会丢失。是的,你是对的,因为我们伪造了千位分隔符,所以我们必须在格式字符串中提供尽可能多的数字。

以上是关于如何使用 Apache POI (SXSSF) 为特定单元格设置数据(数字)格式区域设置?的主要内容,如果未能解决你的问题,请参考以下文章

java poi Excel大数据量导入怎么提高速度

使用 SXSSF POI 编写大型 Excel 工作表

使用apache poi - 检测到Zip Bomb

HSSFXSSF和SXSSF区别以及Excel导出优化

https://poi.apache.org/components/spreadsheet/index.html(翻译1)

基于SXSSF (Streaming Usermodel API)的写文件