使用 NPOI 、aspose實現execl模板公式計算


   最近接到一個需求,公司財務有個execl里面已經寫滿了各種計算公式多個sheet公式嵌套等,bd直接往execl中指定的單元格填充數據,execl中的公式可以算出所有的測算結果。現在這個需要做到系統中去,由於公式過於復雜而且多變(財務會已經調整了好幾個版本了),於是不將計算邏輯放在系統中實現。在模塊的頁面中填數據,並返回計算結果到頁面。

  開始做使用npoi-2.21 時發現一個問題,在某一個單元格中計算出來數據有誤差,於是做了一個實驗讀取execl模板轉成IO流輸出從頁面下載出來,

對兩個模板填一樣的數據,發現經過  workbook = new XSSFWorkbook(execlStream);下載出的模板數據出現誤差,於是升級npoi到2.3.0。重復實驗這回模板正確了。

      Execl中需要填寫的位置坐標是已知的,於是將這些坐標做成一張配置表並存入。

    獲取到workbook 並指定 將要操作的sheet;

 IWorkbook workbook= new XSSFWorkbook(execlStream);
ISheet sheet
= workbook.GetSheet("指定sheet")

       接下來設置指定單元格的值

 sheet.GetRow(Y).GetCell(X).SetCellValue(value);

    我們從execl中看到的坐標一般的都是 A1、B2、C3 然而GetRow()於GetCell()的參數設定為int類型,於是需要一個轉換坐標將我們的A1...這些坐標做轉換。

 /// <summary>
/// 將Excel坐標轉換成10進制坐標, Item1 Row ,Item2 Column
/// </summary>
/// <param name="strCoordinate"></param>
/// <returns></returns>
private Tuple<int, int> TransferCoordinate(string strCoordinate)
{
int rowNumber = 0, columnNumber = 0;
string strRowNum, strColumnNum;
//獲得換行數
MatchCollection collection = Regex.Matches(strCoordinate, @"\d+");
strRowNum
= collection[0].ToString();
rowNumber
= int.Parse(strRowNum);
//獲得列數
collection = Regex.Matches(strCoordinate, @"[A-Z]{1,3}");
strColumnNum
= collection[0].ToString();
columnNumber
= CalColumnNum(strColumnNum);
return new Tuple<int, int>(rowNumber - 1, columnNumber - 1); ;
}

/// <summary>
/// 獲得Excel 列坐標
/// </summary>
/// <param name="strCol"></param>
/// <returns></returns>
private int CalColumnNum(string strCol)
{
int num = 0, charNum;
var charArr = strCol.ToUpper().Trim().ToCharArray();
for (int i = charArr.Length - 1, j = 0; i >= 0; i--, j++)
{
charNum
= (int)charArr[i] - 64;
num
+= (int)Math.Pow(26, j) * charNum;
}

return num;
}

通過轉換得到   Tuple<int, int> 得到單元格的坐標賦值

sheet.GetRow(coordinate.Item1).GetCell(coordinate.Item2).SetCellValue(number);

設置 sheet.ForceFormulaRecalculation = true; npoi提供用於重新計算公式

cell.SetCellFormula()  可以在后台代碼中設置單元格公式

到此處,對模板的寫入已經公式計算已經完成。可以直接做流輸出下載。。。

  我們的需求是將這計算的結果返回到頁面中去顯示,已經在內存中做了寫入於公式計算,繼續使用當前的workbook做值讀取

IFormulaEvaluator evaluator = new XSSFFormulaEvaluator(workbook);
foreach (var item in daseInfo)
{
   Tuple
<int, int> ElementCoordinate = TransferCoordinate(item.PostionCode);//坐標轉換

      ICell cell = sheet.GetRow(ElementCoordinate.Item1).GetCell(ElementCoordinate.Item1);
       cell = evaluator.EvaluateInCell(cell);   string value =cell.NumericCellValue
 }

 

   本人在這個地方再次出現了讀取出來的值存在誤差的BUG,大概一百個單元格的讀取,全都使用公式,有兩個單元格值存在誤差。使用上面的驗證,模板轉換流,流轉回模板都沒問題,於是發了封反饋郵件,沒有出現此問題的朋友可以使用以上方式。

確認為npoi讀取bug,確定使用aspose  16.12版,由於沒有授權,在使用過程中發現aspose對於單元格寫入做了限制,寫入無效,但是讀取execl是可以的,而且讀寫更方便,對於公式支持也足夠強大,問題是要錢....錢....錢...公司不出錢,低版本的破解版對於公式的支持不足,於是將兩個控件混合使用,NOPI做寫入,aspose做讀取。

        //將workbook轉化成流
    MemoryStream stream = new MemoryStream();      workbook.Write(stream);
    //aspose讀取流做讀取      Aspose.Cells.Workbook work
= new Aspose.Cells.Workbook(stream);
Aspose.Cells.Cells c
= work.Worksheets["填寫的sheet"].Cells;
work.CalculateFormula();
////獲取經過公式計算的數據------
          //循環坐標 aspose支持string格式的坐標參數也就是 A1 A2
foreach (var item in daseInfo) {
var value = c[item.PostionCode].StringValue;

}

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com