好的,所以我有一个包含15页完整公式的Excel电子表格。我没有保密协议,无法向您显示电子表格。我需要以编程方式输入Web用户提交的值,计算输出并将结果返回给用户。
将电子表格的计算转换为纯代码对于项目预算来说将花费太长时间。
我尝试使用 PhpSpreadsheet :-
$workbook = \PhpOffice\PhpSpreadsheet\IOFactory::load("modeller.xlsx");
$sheet = $workbook->getSheet(1);
$c13 = $sheet->getCell('C13')->getValue();
$c43 = $sheet->getCell('C43')->getValue();
print_r(['C13 Before calc' => $c13, 'C43 Before calc' => $c43]);
$c13 = $sheet->getCell('C13')->setValue(12000);
$c43 = $sheet->getCell('C43')->getCalculatedValue();
print_r(['C13 After calc' => $c13, 'C43 After calc' => $c43]);
但是它不能处理复杂性-尝试并运行计算需要花费很多时间,然后才陷入Fatal error: Maximum function nesting level of '256' reached, aborting!
。
我还尝试学习一些.NET,并使用了 EPPlus :-
var fi = new FileInfo(@"C:\dotnet\webapps\test\modeller.xlsx");
using (var p = new ExcelPackage(fi))
{
var ws = p.Workbook.Worksheets["Inputs & Outputs"];
Console.WriteLine("\tBefore calc Cell(C13).Value={0}", ws.Cells["C13"].Value);
Console.WriteLine("\tBefore calc Cell(C43).Value={0}", ws.Cells["C43"].Value);
ws.Cells["C13"].Value = 12000;
ws.Calculate();
Console.WriteLine("\tAfter calc Cell(C13).Value={0}", ws.Cells["C13"].Value);
Console.WriteLine("\tAfter calc Cell(C43).Value={0}", ws.Cells["C43"].Value);
}
尽管运行速度比PhpSpreadsheet快,但它仍然太慢并且始终无法计算输出-该值始终为#VALUE!
。
我最后的选择是使用 COM 直接与Excel副本进行交互并运行计算:-
$xl = new COM("Excel.Application");
$xl->Visible = false;
$xl->DisplayAlerts = false;
$file = 'C:\\wamp\\www\\test\\modeller.xlsx';
$wb = $xl->Workbooks->Open($file);
$ws = $wb->Worksheets('Inputs & Outputs');
$c13 = $ws->Range('C12')->Value;
$c43 = $ws->Range('C43')->Value;
print_r(['C13 Before calc' => $c13, 'C43 Before calc' => $c43]);
$ws->Range('C12')->Value = 12000;
$ws->Calculate();
$c13 = $ws->Range('C12')->Value;
$c43 = $ws->Range('C43')->Value;
print_r(['C13 After calc' => $c13, 'C43 After calc' => $c43]);
$wb->Close();
这可以工作(经过多年对Component Services的了解),并且在我的开发机器上仅花费约2秒的时间。但是我是worried about the scalability of this approach-可能有数百个并发请求都打开一个Excel实例。
我真的不想使用COM。还有我没有考虑过的另一种方法吗?