詳細教程:
NPOI使用手冊——c# - vv彭 - 博客園 (cnblogs.com)
1,NPOI讀取Excel高低版本兼容性問題
報錯1:NPOI.POIFS.FileSystem.OfficeXmlFileException HResult=0x80070057 Message=The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process
報錯2:NPOI.POIFS.FileSystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)
原因:這是因為NPOI讀取2003時使用的是HSSFWorkbook,更高版本讀取需要使用XSSFWorkbook
解決方式:
將代碼中HSSFWorkbook修改為XSSFWorkbook,最好是導入文件時選擇版本,這樣處理更好
IWorkbook workbook = new XSSFWorkbook(file);
2,NPOI讀取Excel帶計算公式的值
/// <summary>
/// 根據填充后的綜合判定表來綜合判定是否OK(獲取帶公式列的值)
/// </summary>
/// <param name="filePath">填充后的綜合判定表打印版的文件路徑</param>
public static void Step4(FilePath filePath)
{
XSSFWorkbook workbook;
XSSFFormulaEvaluator evalor = null;
using (FileStream fs = File.Open(filePath.PrintMatchFilePath, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
{
//把xls文件讀入workbook變量里,之后就可以關閉了
workbook = new XSSFWorkbook(fs);
//【帶公式取值步驟1】創建當前sheet 的動態公式計算器
evalor = new XSSFFormulaEvaluator(workbook);
fs.Close();
}
ISheet sheet = workbook.GetSheetAt(0);
int rowCount = sheet.LastRowNum;
int StandardTotalCount = 0;
int OKTotalCount = 0;
ICell cellObj = sheet.GetRow(21).GetCell(3);
var cellType = cellObj.CellType;
switch (cellType)
{
case CellType.Formula:
//【帶公式取值步驟2】針對公式列 進行動態計算;注意:公式暫時只支持 數值 字符串類型
var formulaValue = evalor.Evaluate(cellObj);
if (formulaValue.CellType == CellType.Numeric)
{
double b = formulaValue.NumberValue;
StandardTotalCount = Convert.ToInt32(b);
}
else if (formulaValue.CellType == CellType.String)
{
string s = formulaValue.StringValue;
}
break;
default:
break;
}
ICell cellObj2 = sheet.GetRow(21).GetCell(4);
var cellType2 = cellObj2.CellType;
switch (cellType2)
{
case CellType.Formula:
//針對公式列 進行動態計算;注意:公式暫時只支持 數值 字符串類型
var formulaValue = evalor.Evaluate(cellObj2);
if (formulaValue.CellType == CellType.Numeric)
{
double b = formulaValue.NumberValue;
OKTotalCount = Convert.ToInt32(b);
}
else if (formulaValue.CellType == CellType.String)
{
string s = formulaValue.StringValue;
}
break;
default:
break;
}
if (StandardTotalCount == OKTotalCount)
{
sheet.GetRow(21).GetCell(6).SetCellValue("OK");
}
else
{
sheet.GetRow(21).GetCell(6).SetCellValue("NG");
}
//轉為字節數組
MemoryStream stream = new MemoryStream();
workbook.Write(stream);
var buf = stream.ToArray();
//保存為Excel文件 這種方式能保存.xls和.xlsx文件
using (FileStream fs = new FileStream(filePath.PrintMatchFilePath, FileMode.Create, FileAccess.Write))
{
fs.Write(buf, 0, buf.Length);
fs.Flush();
}
}
3,元格帶有公式的值不能自動更新
ISheet sheet = workbook.GetSheetAt(0);
//解決單元格帶有公式的值不能自動更新
//解決辦法:在程序最后添加一句(關閉文件前),使得sheetdata自動重算【我測試過不用放在關閉文件前也可以的】
sheet.ForceFormulaRecalculation = true;
4,設置打印頁面縮放和自適應列寬
/// <summary>
/// 自適應列寬和打印頁縮放
/// </summary>
/// <param name="filePath">excel文件路徑</param>
/// <param name="scale">縮放比例(77,80,100等)</param>
public static void AutoColumnWidth(string filePath,short scale=80)
{
//【1】打開excel文件的第幾張表,第幾行的數據,返回一個字典{列名:列的索引}
//字典的作用:可以根據列名快速找到對應的列索引
Dictionary<string, int> dicData = ExcelHelper.GetDataDictionary(filePath, 1, 1);
bool isCompatible = ExcelHelper.GetIsCompatible(filePath);
IWorkbook workbook = null;
using (FileStream fs = File.Open(filePath, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
{
//把xls文件讀入workbook變量里,之后就可以關閉了
workbook = ExcelHelper.CreateWorkbook(isCompatible, fs);
fs.Close();
}
ISheet sheet = workbook.GetSheetAt(0);
int rowCount = sheet.LastRowNum;
for (int col = 0; col < sheet.GetRow(0).LastCellNum; col++)
{
//自適應列寬
sheet.AutoSizeColumn(col);
}
//sheet.PrintSetup.FitWidth = 1;
//sheet.PrintSetup.FitHeight = 0;
//設置打印頁面縮放比例
sheet.PrintSetup.Scale = scale;
#region 非常的耗時,不推薦使用
////開始遍歷【遍歷行操作】
//for (int r = 1; r <= rowCount; r++) //從第二行開始遍歷
//{
// IRow currentRow = sheet.GetRow(r); //讀取當前行數據
// if (currentRow == null) //如果為空,重新創建一行,防止null報錯
// {
// sheet.CreateRow(r);
// currentRow = sheet.GetRow(r);
// }
// for (int i = 0; i < currentRow.LastCellNum; i++)
// {
// //sheet.AutoSizeColumn(i);//非常的耗時,不推薦用
// }
//}
#endregion
//轉為字節數組
MemoryStream stream = new MemoryStream();
workbook.Write(stream);
var buf = stream.ToArray();
//保存為Excel文件 這種方式能保存.xls和.xlsx文件
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
fs.Write(buf, 0, buf.Length);
fs.Flush();
}
}
行或單元格為null報錯問題:
private void Step6()
{
//【1】打開excel文件的第幾張表,第幾行的數據,返回一個字典{列名:列的索引}
//字典的作用:可以根據列名快速找到對應的列索引
Dictionary<string, int> dicData = ExcelHelper.GetDataDictionary(filePath.CheckFilePath, 1, 2);
bool isCompatible = ExcelHelper.GetIsCompatible(filePath.CheckFilePath);
IWorkbook workbook = null;
using (FileStream fs = File.Open(filePath.CheckFilePath, FileMode.Open,
FileAccess.Read, FileShare.ReadWrite))
{
//把xls文件讀入workbook變量里,之后就可以關閉了
workbook = ExcelHelper.CreateWorkbook(isCompatible, fs);
fs.Close();
}
ICellStyle sOK = workbook.CreateCellStyle(); //設置單元格的背景顏色需要用到的代碼
sOK.FillForegroundColor = HSSFColor.SeaGreen.Index; //設置單元格的背景顏色需要用到的代碼
sOK.FillPattern = FillPattern.SolidForeground; //設置單元格的背景顏色需要用到的代碼
ICellStyle sNOK = workbook.CreateCellStyle(); //設置單元格的背景顏色需要用到的代碼
sNOK.FillForegroundColor = HSSFColor.Red.Index; //設置單元格的背景顏色需要用到的代碼
sNOK.FillPattern = FillPattern.SolidForeground; //設置單元格的背景顏色需要用到的代碼
ICellStyle sCheck = workbook.CreateCellStyle(); //設置單元格的背景顏色需要用到的代碼
sCheck.FillForegroundColor = HSSFColor.Yellow.Index; //設置單元格的背景顏色需要用到的代碼
sCheck.FillPattern = FillPattern.SolidForeground; //設置單元格的背景顏色需要用到的代碼
ISheet sheet = workbook.GetSheetAt(0);
int rowCount = sheet.LastRowNum;
//開始遍歷【遍歷行操作】
for (int r = 1; r <= rowCount; r++) //從第二行開始遍歷
{
IRow currentRow = sheet.GetRow(r); //讀取當前行數據
if (currentRow == null) //如果為空,重新創建一行,防止null報錯
{
sheet.CreateRow(r);
currentRow = sheet.GetRow(r);
}
//物料編碼
if (currentRow.GetCell(dicData["物料編碼"]) == null)
{
currentRow.CreateCell(dicData["物料編碼"]);
};
string materialNumber = currentRow.GetCell(dicData["物料編碼"]).ToString();
//訂單編號
string orderNumber = currentRow.GetCell(dicData["訂單編號"]).ToString();
//行號
string lineNumber = currentRow.GetCell(dicData["行號"]).ToString();
//未到貨數量
string orderQuantity = currentRow.GetCell(dicData["未到貨數量"]).ToString();
int iOrderQuantity;
iOrderQuantity=int.TryParse(orderQuantity, out iOrderQuantity)? iOrderQuantity : -1;
#region 避開第二步的標識
if (currentRow.GetCell(dicData["供應商是否更改供應商承諾交期(Y/N)"]) == null)
{
currentRow.CreateCell(dicData["供應商是否更改供應商承諾交期(Y/N)"]);
};
if (currentRow.GetCell(dicData["供應商是否更改供應商承諾交期(Y/N)"]).ToString() == "N") continue;
#endregion
//如果 現存量 中有 這個型號 .
if (dicLatestPrice.ContainsKey(materialNumber))
{
//獲取客戶的采購數量
string purchaseQuantity = currentRow.GetCell(dicData["采購訂單總數量"]).ToString(); ;
int iPurchaseQuantity;
int.TryParse(purchaseQuantity, out iPurchaseQuantity);
//獲取 可用量
int iAvailableQuantity = dicLatestPrice[materialNumber].AvailableQuantity;
// 獲取 現存量
int iOnHandQuantity = dicLatestPrice[materialNumber].OnHandQuantity;
//如果品牌是歐姆龍的
if (dicLatestPrice[materialNumber].Brand == "歐姆龍")
{
//且該物料編碼的 采購入庫待入量 大於等於 未到貨數量
if (dicLatestPrice[materialNumber].PurchaseQuantity > iOrderQuantity)
{
currentRow.GetCell(dicData["供應商是否更改供應商承諾交期(Y/N)"]).SetCellValue("N");
currentRow.GetCell(dicData["供應商是否更改供應商承諾交期(Y/N)"]).CellStyle = sOK;
if (currentRow.GetCell(dicData["目前物料的狀態"]) == null)
currentRow.CreateCell(dicData["目前物料的狀態"]);
currentRow.GetCell(dicData["目前物料的狀態"]).SetCellValue(dicLatestPrice[materialNumber].Brand + "已提貨");
currentRow.GetCell(dicData["目前物料的狀態"]).CellStyle = sOK;
}
}
}
}
//轉為字節數組
MemoryStream stream = new MemoryStream();
workbook.Write(stream);
workbook.Close();//關閉工作薄
var buf = stream.ToArray();
//保存為Excel文件 這種方式能保存.xls和.xlsx文件
using (FileStream fs = new FileStream(filePath.CheckFilePath, FileMode.Create, FileAccess.Write))
{
fs.Write(buf, 0, buf.Length);
fs.Flush();
fs.Dispose();//釋放文件流
}
}
