英文:
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 ("Test population mean in two different populations are same or not");
System.out.println ("This program works only for two-tailed ");
Scanner in = new Scanner(System.in);
System.out.println ("What is population mean?:");
double m = in.nextDouble();
System.out.println ("How many samples are taken from population?:");
double n = in.nextDouble();
System.out.println ("What is Sample mean?:");
double X = in.nextDouble();
System.out.println ("What is unbiased variance for population:");
double U = in.nextDouble();
System.out.println ("What is Level of Significance (Type with %-value)");
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 ("Degree of freedom is " + a);
System.out.println ("Test statistic is " + 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();
}
}
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.
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 poi
的Workbook
打开,以便能够追加内容。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 Excel
is 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("SUM(" + l +"," + a + ")");
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("TINV(" + l +"," + a + ")");
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("TINV", 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("TINV", TINV);
System.out.println ("Test population mean in two different populations are same or not");
System.out.println ("This program works only for two-tailed ");
Scanner in = new Scanner(System.in);
System.out.println ("What is population mean?:");
double m = in.nextDouble();
System.out.println ("How many samples are taken from population?:");
double n = in.nextDouble();
System.out.println ("What is Sample mean?:");
double X = in.nextDouble();
System.out.println ("What is unbiased variance for population:");
double U = in.nextDouble();
System.out.println ("What is Level of Significance (Type with %-value)");
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 ("Degree of freedom is " + a);
System.out.println ("Test statistic is " + 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("TINV(" + l +"," + a + ")");
try {
evaluator.evaluateFormulaCell(cell2_3);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
cell2_4.setCellFormula("SUM(" + l +"," + a + ")");
try {
evaluator.evaluateFormulaCell(cell2_4);
} catch (org.apache.poi.ss.formula.eval.NotImplementedException notImplEx) {
notImplEx.printStackTrace();
}
FileOutputStream out = null;
try {
out = new FileOutputStream("T-inverse.xlsx");
wb.write(out);
} catch(IOException e) {
System.out.println("Write: " + e.toString());
} finally {
try {
out.close();
wb.close();
} catch(IOException e) {
System.out.println("Close: " + e.toString());
}
}
}
public static void read_excel() throws IOException {
for (int q=3;q<5;q++) {
XSSFWorkbook book = new XSSFWorkbook("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();
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论