簡體   English   中英

如何在 Apache POI 5.1.0 中使用數組溢出

[英]How to use Array Spilling with Apache POI 5.1.0

使用Apache POI生成excel文件,是否可以防止Excel在公式中添加隱式交集運算符(@)?

例如,使用以下代碼,我想要做的是使用Excel Array Spilling behavior將列內的所有值從 A 復制到 K。 但是,當使用 Excel Desktop(版本 16.54)打開文件時,它會自動在公式中添加 @ 運算符。

在工作簿工作sheet內部,在單元格 A1 中,而不是=IF(otherSheet!A:K=""; ""; otherSheet!A:K) ,我得到=@IF(@otherSheet!A:K=""; ""; otherSheet!A:K)沒有相同的結果,因為我只從anotherSheet獲取 A1 內的值。

import org.apache.poi.ss.usermodel.CellType
import org.apache.poi.xssf.usermodel.XSSFWorkbook

import java.io.FileOutputStream
import java.nio.file._

object Main {
  def main(args: Array[String]): Unit = {

    val workbook = new XSSFWorkbook()
    val sheet = workbook.createSheet("sheet")
    val row = sheet.createRow(0)
    val cell = row.createCell(0, CellType.FORMULA)

    // Filling dummy data to another sheet
    val otherSheet = workbook.createSheet("otherSheet")
    val otherRow = otherSheet.createRow(0)
    for (i <- 0 to 10) {
      otherRow.createCell(i, CellType.STRING).setCellValue("Something")
    }

    // Copying values
    val otherSheetContent = f"otherSheet!A:K"
    cell.setCellFormula(f"""IF($otherSheetContent="", "", $otherSheetContent)""")
    println(cell.getCellFormula) // IF(otherSheet!A:K="", "", otherSheet!A:K)

    // Saving file
    val file = Paths.get("workbook.xlsx")
    workbook.write(new FileOutputStream(file.toFile))

  }
}

您不能在 Apache POI 5.1.0 中使用動態數組公式和溢出數組行為 溢出數組行為是在 Excel 365 版中引入的。它在以前的版本中不可用。 Apache POI 基於 Excel 2007 發布的Office Open XML 。因此使用 Apache POI 生成的 Excel 文件是 Excel 2007 文件。

為什么添加@ 這在隱式交集運算符的“我們何時將 @ 添加到舊公式中?”一節中講述:@

一般來說,如果函數是在舊版本的 Excel 中編寫的,則返回多單元格區域或數組的函數將以 @ 為前綴。 ... 一個常見的例外是如果它們被包裝在一個接受數組或范圍的函數中(例如 SUM() 或 AVERAGE())。

所以添加了@是因為IF不希望它的任何參數中有一個數組。

使用 Apache POI 唯一可以實現的是設置舊數組公式。 見示例:

import java.io.FileOutputStream;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;

class CreateExcelArrayFormula {
    
 static void setArrayToFormula(XSSFCell cell, String ref) {
  if (cell.getCTCell().getF() != null) {
   cell.getCTCell().getF().setT(org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellFormulaType.ARRAY);
   cell.getCTCell().getF().setRef(ref);
  }      
 }

 public static void main(String[] args) throws Exception {

  try (
       Workbook workbook = new XSSFWorkbook(); FileOutputStream fileout = new FileOutputStream("Excel.xlsx") ) {

   Sheet sheet = workbook.createSheet();
   Row row;
   Cell cell;
   
   // Filling dummy data to another sheet
   Sheet otherSheet = workbook.createSheet("otherSheet");
   for (int r = 0; r < 5; r++) {
    row = otherSheet.createRow(r);
    for (int c = 0; c < 11; c++) {
     row.createCell(c).setCellValue("OS-R" + (r+1) + "C" + (c+1));
    }
   }
   
   row = sheet.createRow(0);
   cell = row.createCell(0);
   cell.setCellFormula("IF(otherSheet!A1:K5=\"\", \"\", otherSheet!A1:K5)");
   if (cell instanceof XSSFCell) {
    setArrayToFormula((XSSFCell)cell, "A1:K5");
   }

   workbook.write(fileout);
  }

 }
}

但是您是否應該使用遺留數組公式的溢出數組行為來做這樣的事情? 不,你不應該,在我看來。 如果您使用公式=IF(otherSheet!A:K="", "", otherSheet!A:K)使用溢出數組行為,則生成的文件將非常大。 這是因為完整的列引用A:K跨越 1,048,576 行。 遺留數組也是如此。 永遠不應該使用具有完整列引用的數組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM