Excel 97-2003 (.xls) 中的单元格样式丢失或未显示

Cell style is lost or not displayed in Excel 97-2003 (.xls)

我正在使用 Apache POI 库将数据导出到 Excel。我已经尝试了所有最新版本(3.17、4.1.2 和 5.2.1)。

我对 Excel 97 (.xls) 格式的单元格样式有疑问。单元格样式在一定数量的列后以某种方式丢失(或不显示)。

这是我的示例代码:

private void exportXls() {
  try (
      OutputStream os = new FileOutputStream("test.xls");
      Workbook wb = new HSSFWorkbook();) {
    Sheet sh = wb.createSheet("test");
    Row r = sh.createRow(0);
    for (int i = 0; i < 50; i++) {
      Cell c = r.createCell(i);
      c.setCellValue(i + 1);
      
      CellStyle cs = wb.createCellStyle();
      cs.setFillBackgroundColor(IndexedColors.WHITE.index);
      cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
      cs.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
      c.setCellStyle(cs);
    }
    wb.write(os);
    os.flush();
  } catch (Exception e) {
    e.printStackTrace();
  }
}

以及 MS 查看的结果 Excel 2019 Viewed by MS Excel

如您所见,style/format 在第 43 个单元格后丢失。

但是,当我通过 XLS Viewer Free(来自 Microsoft Store)或 Google Sheets(在线)等其他应用程序打开同一文件时,style/format 仍然存在并且显示良好。 Viewed by XLS Viewer Free Viewed by Google Sheets

有人能告诉我这是怎么回事吗?

我的代码中是否遗漏了什么?

MS Excel 中是否有任何隐藏设置导致此问题?

谢谢。

使用 apache poi 为每个单元格创建单元格样式不是一个好主意。单元格样式存储在 Excel 中的工作簿级别。如果可能,工作表和单元格共享单元格样式。

而且所有 Excel 版本中不同单元格样式的最大数量都有限制。二进制 *.xls 的限制小于 OOXML *.xlsx.

的限制

限制本身不能成为您获得结果的唯一原因。但似乎 Excel 对工作簿中 50 个完全相同的单元格样式不是很满意。这些都是内存浪费,因为所有 50 个单元格都共享相同的样式,因此只需要一种共享样式。

解决方案是:

在单元格创建循环之外的工作簿级别创建单元格样式,并且仅将样式设置到循环中的单元格。

示例:

 private static void exportXlsCorrect() {
  try (
   OutputStream os = new FileOutputStream("testCorrect.xls");
   Workbook wb = new HSSFWorkbook();) {
       
   CellStyle cs = wb.createCellStyle();
   cs.setFillBackgroundColor(IndexedColors.WHITE.index);
   cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
   cs.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
    
   Sheet sh = wb.createSheet("test");
   Row r = sh.createRow(0);
   for (int i = 0; i < 50; i++) {
    Cell c = r.createCell(i);
    c.setCellValue(i + 1);
      
    c.setCellStyle(cs);
   }
   wb.write(os);
   os.flush();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

有时在创建单元格之前不可能知道所有可能需要的单元格样式。然后可以使用CellUtil。这有一个方法 CellUtil.setCellStyleProperties 可以为单元格设置特定的样式属性。只有在需要时,才会在工作簿级别创建新的单元格样式。如果已经存在,则使用当前的单元格样式。

示例:

 private static void exportXlsUsingCellUtil() {
  try (
   OutputStream os = new FileOutputStream("testUsingCellUtil.xls");
   Workbook wb = new HSSFWorkbook();) {
            
   Sheet sh = wb.createSheet("test");
   Row r = sh.createRow(0);
   for (int i = 0; i < 50; i++) {
    Cell c = r.createCell(i);
    c.setCellValue(i + 1);
    
    java.util.Map<java.lang.String,java.lang.Object> properties = new java.util.HashMap<java.lang.String,java.lang.Object>();
    properties.put(org.apache.poi.ss.util.CellUtil.FILL_BACKGROUND_COLOR, IndexedColors.WHITE.index);
    properties.put(org.apache.poi.ss.util.CellUtil.FILL_FOREGROUND_COLOR, IndexedColors.LIGHT_BLUE.getIndex());
    properties.put(org.apache.poi.ss.util.CellUtil.FILL_PATTERN, FillPatternType.SOLID_FOREGROUND);
    org.apache.poi.ss.util.CellUtil.setCellStyleProperties(c, properties);

   }
   wb.write(os);
   os.flush();
  } catch (Exception e) {
   e.printStackTrace();
  }
 }