2017-09-25 1 views
1

Apache POI 3.17 (현재)을 사용 중입니다. HSSFCell.setFormula()를 사용하여 "A1 + 17"과 같은 수식을 삽입하면 작동합니다. 스트리밍 모드에서 동일한 작업을 수행 할 때 SXSSFCell.setFormula()를 사용하면 입력 행에 수식이 표시되지만 셀에 표시된 결과는 항상 0입니다.Apache POI는 어떻게 스트리밍 모드에서 수식을 사용할 수 있습니까?

셀을 사용해 보았습니다. NUMERIC W FORMULA를 입력하십시오. 다음은 최소한의 작동하지 않는 예제입니다.

final SXSSFWorkbook wb = new SXSSFWorkbook(); 
final SXSSFSheet sheet = wb.createSheet("Test-S"); 
final SXSSFRow row = sheet.createRow(0); 

final SXSSFCell cell1 = row.createCell(0); 
cell1.setCellType(CellType.NUMERIC); 
cell1.setCellValue(124); 

final SXSSFCell formulaCell1 = row.createCell(1); 
formulaCell1.setCellType(CellType.FORMULA); 
formulaCell1.setCellFormula("A1 + 17"); 

final SXSSFCell formulaCell2 = row.createCell(2); 
formulaCell2.setCellType(CellType.NUMERIC); 
formulaCell2.setCellFormula("A1+18"); 

FileOutputStream os = new FileOutputStream("/tmp/test-s.xlsx"); 
wb.write(os); 
wb.close(); 
os.close(); 

입력란에 수식이 올바르게 표시되지만 3 개의 셀은 124/0/0로 표시됩니다.

힌트를 보내 주시면 감사하겠습니다.

답변

2

나를 위해 Excel 2016에서 작동합니다. 샘플 파일을 열 때 셀에 올바른 결과가 나타납니다. 아마 엑셀의 이전 버전은 약간 다르게 이것을 처리, 그것뿐만 아니라 당신을 위해 작동 할 것입니다 다음과 같은 두 가지

// evaluate all formulas and store cached results 
wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); 
// suggest to Excel to recalculate the formulas itself as well 
sheet.setForceFormulaRecalculation(true); 

희망 한 두의

와 공식 평가를 강제로 시도하십시오.

+0

고마워요! evaluateAll()이 트릭을 수행했습니다. 그러나 나는 제안 된 진술을 모두 지킬 것이다. – Renardo

+0

몇 가지 추가 설명 : 어떤 경우에는 evaluateAll()이 행이 이미 플러시되었다는 예외를 throw 할 수 있습니다. 이 경우 evaluateFormulaCellEnum (cell)을 사용할 수 있습니다. – Renardo

1

물론 LibreOffice를 사용한다고 언급해야합니다. 이제는 LibreOffice가 의도적으로 Excel에서 만든 수식을 다시 계산하지 않고 POI 시트를 Excel로 만든 것으로 간주합니다.

https://ask.libreoffice.org/en/question/12165/calc-auto-recalc-does-not-work/을 참조하십시오.

(도구 - 옵션 - LibreOffice Calc - 수식 - 파일로드시 다시 계산) LibreOffice 설정을 변경하면 도움이됩니다.

1

SXSSFCell을 수식 셀로 사용하는 경우에만 OpenOffice/Libreoffice에서이 문제가 발생하는 이유에 대한 대답에 대한 대답이 없습니다. 수식 셀로 XSSFCell을 사용할 때 발생하지 않습니다.

대답은 SXSSFCell항상은 수식이 전혀 평가되지 않더라도 셀 값을 사용합니다. 그리고 최악의 경우는 수식이 전혀 평가되지 않은 경우 값 0 (영)을 사용한다는 것입니다. 이것은 수학에서 가치 0을 근본적으로 오용하는 것입니다. 값 0은 명시 적으로 이 아니며은 값이 없거나 알 수없는 값임을 의미합니다. 그것은 값 0이 있고 그 외에는 아무것도 없다는 것을 의미합니다. 따라서 값 0은 이 아니고이 계산되지 않은 수식의 캐시 된 수식 결과로 사용되어야합니다. 대신 값은 수식이 평가 될 때까지 사용해야합니다. 정확하게는 XSSFCell입니다.

그래서 정확히 맞는 대답은 apache poi이 코드 SXSSFCell을 수정해야한다는 것입니다. 이 때까지

해결 방법 :

import java.io.FileOutputStream; 

import org.apache.poi.xssf.streaming.*; 

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

import java.lang.reflect.Field; 

import java.util.TreeMap; 

public class CreateExcelSXSSFFormula { 

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

    SXSSFWorkbook wb = new SXSSFWorkbook(); 

    SXSSFSheet sheet = wb.createSheet("Test-S"); 
    SXSSFRow row = sheet.createRow(0); 

    SXSSFCell cell = row.createCell(0); 
    cell.setCellValue(124); 

    SXSSFFormulaonlyCell formulacell = new SXSSFFormulaonlyCell(row, 1); 
    formulacell.setCellFormula("A1+17"); 

    cell = row.createCell(2); 
    cell.setCellFormula("A1+17"); 

    formulacell = new SXSSFFormulaonlyCell(row, 3); 
    formulacell.setCellFormula("A1+18"); 

    cell = row.createCell(4); 
    cell.setCellFormula("A1+18"); 

    wb.write(new FileOutputStream("test-s.xlsx")); 
    wb.close(); 
    wb.dispose(); 

} 

private static class SXSSFFormulaonlyCell extends SXSSFCell { 

    SXSSFFormulaonlyCell(SXSSFRow row, int cellidx) throws Exception { 
    super(row, CellType.BLANK); 
    Field _cells = SXSSFRow.class.getDeclaredField("_cells"); 
    _cells.setAccessible(true); 
    @SuppressWarnings("unchecked") //we know the problem and expect runtime error if it possibly occurs 
    TreeMap<Integer, SXSSFCell> cells = (TreeMap<Integer, SXSSFCell>)_cells.get(row); 
    cells.put(cellidx, this); 
    } 

    @Override 
    public CellType getCachedFormulaResultTypeEnum() { 
    return CellType.BLANK; 
    } 

} 

} 
+0

감사합니다 @Axel Richter; 그거 아주 재미있어 보여. 예, SXSSFRow에는 보호 된 메서드 나 멤버가 없으므로이를 확장하는 유일한 방법은 리플렉션입니다. 나는'SXXSFCell'을 본다.'getCachedFormulaResultTypeEnum()'은 더 이상 사용되지 않습니다. 어쩌면 POI 개발자가 현재 해당 주제에 대해 작업하지 않고 있거나 해당 용도를 사용하지 않는 것일 수도 있습니다. – Renardo

+0

@ Renardo : 제공된 해결 방법은 해결책이 아닌 해결 방법 일뿐입니다. 해결책은'SXSSFCell'의 코드를 변경하여 평가되지 않은 공식에 대해 캐시 된 공식 결과로 ** 값 **을 사용하지 않도록하는 것입니다. 그러나'아파치 포이 (apache poi) '의 변경 관리 역시 이상합니다. 오늘 현재, apidocs는'SXSSFCell.getCachedFormulaResultTypeEnum()'과'CellType'을 반환하는'SXSSFCell.getCachedFormulaResultType()'을 사용하지 않습니다. 그러나 실제 버전 3.17에서는 ** getCachedFormulaResultTypeEnum()을 사용하고 거기에'getCachedFormulaResultType()'은'int'를 반환합니다. –

관련 문제