如何使用Apache POI缓存公式单元格

huangapple go评论73阅读模式
英文:

How to cache the formula cell by using Apache POI

问题

我创建了以下代码来创建 Excel 文件,并在之后计算并获取单元格的值,因为我需要在 Excel 中使用函数。(这个函数不受 Apache POI 支持,所以我认为我必须读取缓存/格式化值)

package main;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class WorkbookEvaluator
{
    public static void pop_mean()
    {
        System.out.println("测试两个不同总体的总体均值是否相同");
        System.out.println("此程序仅适用于双尾检验");

        Scanner in = new Scanner(System.in);
        System.out.println("总体均值是多少?:");
        double m = in.nextDouble();

        System.out.println("从总体抽取了多少样本?:");
        double n = in.nextDouble();

        System.out.println("样本均值是多少?:");
        double X = in.nextDouble();

        System.out.println("总体无偏方差是多少?:");
        double U = in.nextDouble();

        System.out.println("显著性水平是多少(以百分比值输入)");
        double L = in.nextDouble();
        double l = L/100;

            double a = n-1;
            double b = X-m;
            double c = Math.sqrt(n);
            double d = Math.sqrt(U);
            double f = d/c;
            double T = b/f;
            System.out.println("自由度为:" + a);
            System.out.println("检验统计量为:" + T);

            Workbook wb = new XSSFWorkbook();
            Sheet sheet = wb.createSheet();
            Row row1 = sheet.createRow(1);
            Row row2 = sheet.createRow(2);

            Cell cell1_1 = row1.createCell(1);
            Cell cell1_2 = row1.createCell(2);
            Cell cell1_3 = row1.createCell(3);
            Cell cell2_3 = row2.createCell(3);
            Cell cell2_4 = row2.createCell(4);

            cell1_1.setCellValue(l);
            cell1_2.setCellValue(a);
            cell2_3.setCellFormula("_xlfn.T.INV.2T(" + l + "," + a + ")");
            cell2_4.setCellFormula("SUM(" + l + "," + a + ")");

            FileOutputStream out = null;
            try {
                out = new FileOutputStream("T-inverse.xlsx");
                wb.write(out);
            } catch(IOException e) {
                System.out.println(e.toString());
            } finally {
                try {
                    out.close();
                } catch(IOException e) {
                    System.out.println(e.toString());
                }
            }
    }

    public static void read_excel() throws IOException
    {
        for (int q=3;q<5;q++)
        {
            XSSFWorkbook book = new XSSFWorkbook("C:\\Users\\shump\\Java\\Population mean Test\\T-inverse.xlsx");
            book.setForceFormulaRecalculation(true);
            XSSFSheet sheet = book.getSheetAt(0);
            sheet.setForceFormulaRecalculation(true);
            XSSFRow row = sheet.getRow(2);
            final DataFormatter dataFormatter = new DataFormatter(); 
            final double formtatedValue = row.getCell((short) q).getNumericCellValue(); 
            System.out.println(formtatedValue);
        }
    }

    public static void main(String[] args) throws IOException
    {    
        pop_mean();
        read_excel();
    }
}

正如从下面的尝试图片中可以看出,它在 Excel 中成功运行。然而,控制台输出将显示为 0.0。我认为这是因为函数不受支持,所以我尝试使用基本函数之一的 SUM 函数进行相同的操作,而且这个函数是受支持的。然而,它并没有起作用。在图片中,D3 是我使用 T.INV.2T 函数的地方。

(图片被省略)

经过一些研究,我发现一篇文章,其中提到当公式值未缓存时,输出将为 0。因此,请告诉我如何缓存该值,或者是否有其他方法可以使用来获取不受支持函数的值。

英文:

I created code as below to create excel file and calculate and get cell value after because I need to use function in excel.(this function is not supported by apache poi, so I think I have to read cached./formatted value)

package main;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class WorkbookEvaluator
{
    public static void pop_mean()
    {
        System.out.println (&quot;Test population mean in two different populations are same or not&quot;);
        System.out.println (&quot;This program works only for two-tailed &quot;);

        Scanner in = new Scanner(System.in);
        System.out.println (&quot;What is population mean?:&quot;);
        double m = in.nextDouble();

        System.out.println (&quot;How many samples are taken from population?:&quot;);
        double n = in.nextDouble();

        System.out.println (&quot;What is Sample mean?:&quot;);
        double X = in.nextDouble();

        System.out.println (&quot;What is unbiased variance for population:&quot;);
        double U = in.nextDouble();

        System.out.println (&quot;What is Level of Significance (Type with %-value)&quot;);
        double L = in.nextDouble();
        double l = L/100;

            double a = n-1;
            double b = X-m;
            double c = Math.sqrt(n);
            double d = Math.sqrt(U);
            double f = d/c;
            double T = b/f;
            System.out.println (&quot;Degree of freedom is &quot; + a);
            System.out.println (&quot;Test statistic is &quot; + T);

            Workbook wb = new XSSFWorkbook();
            Sheet sheet = wb.createSheet();
            Row row1 = sheet.createRow(1);
            Row row2 = sheet.createRow(2);

            Cell cell1_1 = row1.createCell(1);
            Cell cell1_2 = row1.createCell(2);
            Cell cell1_3 = row1.createCell(3);
            Cell cell2_3 = row2.createCell(3);
            Cell cell2_4 = row2.createCell(4);

            cell1_1.setCellValue(l);
            cell1_2.setCellValue(a);
            cell2_3.setCellFormula(&quot;_xlfn.T.INV.2T(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);
            cell2_4.setCellFormula(&quot;SUM(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);

            FileOutputStream out = null;
            try {
                out = new FileOutputStream(&quot;T-inverse.xlsx&quot;);
                wb.write(out);
            } catch(IOException e) {
                System.out.println(e.toString());
            } finally {
                try {
                    out.close();
                } catch(IOException e) {
                    System.out.println(e.toString());
                }
            }
    }

    public static void read_excel() throws IOException
    {
        for (int q=3;q&lt;5;q++)
        {
            XSSFWorkbook book = new XSSFWorkbook(&quot;C:\\Users\\shump\\Java\\Population mean Test\\T-inverse.xlsx&quot;);
            book.setForceFormulaRecalculation(true);
            XSSFSheet sheet = book.getSheetAt(0);
            sheet.setForceFormulaRecalculation(true);
            XSSFRow row = sheet.getRow(2);
            final DataFormatter dataFormatter = new DataFormatter(); 
            final double formtatedValue = row.getCell((short) q).getNumericCellValue(); 
            System.out.println(formtatedValue);
        }
    }

    public static void main(String[] args) throws IOException
    {    
        pop_mean();
        read_excel();
    }
}

As can be see from the attempted picture below, it works successfully in excel. However, consoled output will display 0.0. I thought this is because of function is not supported so I tried same thing by using sum function which is one of the basic function and this function is supported. However, it didn't work. In picture D3 is where I used T.INV.2T function.

如何使用Apache POI缓存公式单元格

Test population mean in two different populations are same or not
This program works only for two-tailed 
What is population mean?:
171.4
How many samples are taken from population?:
9
What is Sample mean?:
172.8
What is unbiased variance for population:
4
What is Level of Significance (Type with %-value)
5
Degree of freedom is 8.0
Test statistic is 2.1000000000000085
0.0
0.0

After few research, I found article which states when the formula value is not cached, output will be 0. So, please tell me how I can cache the value or is there any other way that I can take to get value of non-supported function.

答案1

得分: 1

你似乎误解了apache poi的用途。就Excel而言,它用于创建Excel文件。这意味着它创建的文件可以被Excel打开。当Excel打开工作簿文件时,它将它们仅作为apache poiWorkbook打开,以便能够追加内容。Apache poi不被视为与Excel相同,也不与任何Excel应用程序交互。

所以setForceFormulaRecalculation不是apache poi的设置,而是Excel打开工作簿时的设置。如果将setForceFormulaRecalculation设置为true,则Excel在打开工作簿文件时会重新计算所有公式。这并不意味着apache poi会重新计算所有公式。

要强制apache poi计算公式,需要使用FormulaEvaluator

例如,如果您将代码扩展如下:

...
import org.apache.poi.ss.usermodel.FormulaEvaluator;
...
Workbook wb = new XSSFWorkbook();
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
...
cell2_4.setCellFormula("SUM(" + l + "," + a + ")");
try {
    evaluator.evaluateFormulaCell(cell2_4);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
    notImplEx.printStackTrace();
}
...

那么SUM公式会被计算,cell2_4除了公式外还包含了计算后的数值。

但当然,以下代码:

...
cell2_3.setCellFormula("TINV(" + l + "," + a + ")");
try {
    evaluator.evaluateFormulaCell(cell2_3);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
    notImplEx.printStackTrace();
}
...

将会导致NotImplementedException,因为apache poi中尚未实现TINV函数。

因此,我们需要像开发公式评估中所示的那样进行操作。对于TINV函数,可以这样做:

...
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.functions.*;
import org.apache.commons.math3.distribution.TDistribution;
...
static Function TINV = new Fixed2ArgFunction() {
    public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) {
        try {
            ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
            double dArg1 = OperandResolver.coerceValueToDouble(ve1);
            ValueEval ve2 = OperandResolver.getSingleValue(arg2, srcRowIndex, srcColumnIndex);
            double dArg2 = OperandResolver.coerceValueToDouble(ve2);

            TDistribution t = new TDistribution(dArg2);
            double result = t.inverseCumulativeProbability(1d - dArg1/2d);

            if (Double.isNaN(result) || Double.isInfinite(result)) {
                throw new EvaluationException(ErrorEval.NUM_ERROR);
            }

            return new NumberEval(result);

        } catch (EvaluationException e) {
            return e.getErrorEval();
        }
    }
};
...

然后注册函数:

...
WorkbookEvaluator.registerFunction("TINV", TINV);
...

这样,您可以在代码中使用TINV函数。

完整示例代码已经在您提供的内容中,包含了以上翻译的部分。

英文:

You seems misunderstand what apache poi is made for. In terms of Excel it is made for creating Excel files. That meams it creates files which Excelis able to open then. When it opens workbook files, it opens them as apache poi Workbook only to be able to append content. Apache poi is not thought to be the same as Excel and it does not interact with any Excel application.

So the setForceFormulaRecalculation is not a apache poi setting but a setting for Excel when Excel opens the workbook. If setForceFormulaRecalculation is set true, then Excel recalculates all formulas when Excel opens the workbook file. It does not mean that apache poi recalculates all formulas.

To force apache poi calculating the formulas, FormulaEvaluator needs to be used.

For example if you extend your code as follows:

...
import org.apache.poi.ss.usermodel.FormulaEvaluator;
...
Workbook wb = new XSSFWorkbook();
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
...
cell2_4.setCellFormula(&quot;SUM(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);
try {
evaluator.evaluateFormulaCell(cell2_4);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
...

then the SUM formula gets evaluated and cell2_4 contains the evaluated numeric value additional to the formula.

But of course

...
cell2_3.setCellFormula(&quot;TINV(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);
try {
evaluator.evaluateFormulaCell(cell2_3);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
...

will lead to NotImplementedException since TINV is not yet implemented in apache poi.

So we need to do what is shown in Developing Formula Evaluation. In terms of the TINV function this would be:

...
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.functions.*;
import org.apache.commons.math3.distribution.TDistribution;
...
static Function TINV = new Fixed2ArgFunction() {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) {
try {
ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
double dArg1 = OperandResolver.coerceValueToDouble(ve1);
ValueEval ve2 = OperandResolver.getSingleValue(arg2, srcRowIndex, srcColumnIndex);
double dArg2 = OperandResolver.coerceValueToDouble(ve2);
TDistribution t = new TDistribution(dArg2);
double result = t.inverseCumulativeProbability(1d - dArg1/2d);
if (Double.isNaN(result) || Double.isInfinite(result)) {
throw new EvaluationException(ErrorEval.NUM_ERROR);
}
return new NumberEval(result);
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
};
...

and then

...
WorkbookEvaluator.registerFunction(&quot;TINV&quot;, TINV);
...

Note, I have implemented TINV instead of _xlfn.T.INV.2T since the latter is not able to be implemented that way because of it's strange name. All Excel versions I know also support TINV instead of _xlfn.T.INV.2T.

Complete example extending your code:

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Scanner;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
import org.apache.poi.ss.formula.WorkbookEvaluator;
import org.apache.poi.ss.formula.eval.*;
import org.apache.poi.ss.formula.functions.*;
import org.apache.commons.math3.distribution.TDistribution;
public class WorkbookEvaluatorTest {
static Function TINV = new Fixed2ArgFunction() {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg1, ValueEval arg2) {
try {
ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
double dArg1 = OperandResolver.coerceValueToDouble(ve1);
ValueEval ve2 = OperandResolver.getSingleValue(arg2, srcRowIndex, srcColumnIndex);
double dArg2 = OperandResolver.coerceValueToDouble(ve2);
TDistribution t = new TDistribution(dArg2);
double result = t.inverseCumulativeProbability(1d - dArg1/2d);
if (Double.isNaN(result) || Double.isInfinite(result)) {
throw new EvaluationException(ErrorEval.NUM_ERROR);
}
return new NumberEval(result);
} catch (EvaluationException e) {
return e.getErrorEval();
}
}
};
public static void pop_mean() {
WorkbookEvaluator.registerFunction(&quot;TINV&quot;, TINV);
System.out.println (&quot;Test population mean in two different populations are same or not&quot;);
System.out.println (&quot;This program works only for two-tailed &quot;);
Scanner in = new Scanner(System.in);
System.out.println (&quot;What is population mean?:&quot;);
double m = in.nextDouble();
System.out.println (&quot;How many samples are taken from population?:&quot;);
double n = in.nextDouble();
System.out.println (&quot;What is Sample mean?:&quot;);
double X = in.nextDouble();
System.out.println (&quot;What is unbiased variance for population:&quot;);
double U = in.nextDouble();
System.out.println (&quot;What is Level of Significance (Type with %-value)&quot;);
double L = in.nextDouble();
double l = L/100;
double a = n-1;
double b = X-m;
double c = Math.sqrt(n);
double d = Math.sqrt(U);
double f = d/c;
double T = b/f;
System.out.println (&quot;Degree of freedom is &quot; + a);
System.out.println (&quot;Test statistic is &quot; + T);
Workbook wb = new XSSFWorkbook();
FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator();
Sheet sheet = wb.createSheet();
Row row1 = sheet.createRow(1);
Row row2 = sheet.createRow(2);
Cell cell1_1 = row1.createCell(1);
Cell cell1_2 = row1.createCell(2);
Cell cell1_3 = row1.createCell(3);
Cell cell2_3 = row2.createCell(3);
Cell cell2_4 = row2.createCell(4);
cell1_1.setCellValue(l);
cell1_2.setCellValue(a);
cell2_3.setCellFormula(&quot;TINV(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);
try {
evaluator.evaluateFormulaCell(cell2_3);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
cell2_4.setCellFormula(&quot;SUM(&quot; + l +&quot;,&quot; + a + &quot;)&quot;);
try {
evaluator.evaluateFormulaCell(cell2_4);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
FileOutputStream out = null;
try {
out = new FileOutputStream(&quot;T-inverse.xlsx&quot;);
wb.write(out);
} catch(IOException e) {
System.out.println(&quot;Write: &quot; + e.toString());
} finally {
try {
out.close();
wb.close();
} catch(IOException e) {
System.out.println(&quot;Close: &quot; + e.toString());
}
}
}
public static void read_excel() throws IOException {
for (int q=3;q&lt;5;q++) {
XSSFWorkbook book = new XSSFWorkbook(&quot;T-inverse.xlsx&quot;);
//book.setForceFormulaRecalculation(true);
XSSFSheet sheet = book.getSheetAt(0);
//sheet.setForceFormulaRecalculation(true);
XSSFRow row = sheet.getRow(2);
final DataFormatter dataFormatter = new DataFormatter(); 
final double formtatedValue = row.getCell((short) q).getNumericCellValue(); 
System.out.println(formtatedValue);
}
}
public static void main(String[] args) throws IOException {    
pop_mean();
read_excel();
}
}

huangapple
  • 本文由 发表于 2020年3月4日 07:08:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/60516841.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定