C# 使用 NPOI 处理Excel导入单元格内容是公式问题
引言:今天在处理业务的时候,碰到导入Excel数据不成功的问题,那么就在这里做下笔记吧。
首先,我们有以下的数据。整块业务逻辑的代码在最后会贴上!
1.数值公式示例:
可以看出L3的内容值是80,公式J3*0.2。
我们需要使用判断ICell对象的CellType枚举类型,当=CellType.Formula,则代表单元格是公式类型的。则直接用cell.NumericCellValue取值即可。
对于Excel来讲,除了数值的一些公式以外,还会有日期公式,不过最后都是进入到CellType.Formula判断中,需要另外根据转换出来的数值进行转换成日期类型即可。
2.日期公式示例:
G4的内容我使用的是TODAY公式获取当前日期。
同样的,我们需要使用判断ICell对象的CellType枚举类型,当=CellType.Formula,则代表单元格是公式类型的。则直接用cell.NumericCellValue取值,需要根据取出来的数值进行转换成日期类型即可。
数值转换成日期的处理代码:
long isNumberDateTime = 0;
if (Int64.TryParse(cellVal.ToString(), out isNumberDateTime))
{
//数值型,则转换成日期
DateTime d = DateTime.FromOADate(double.Parse(cellVal.ToString()));
}
转换后的结果:
3.整块业务逻辑的代码:
#region Excel
/// <summary>
/// Excel文件转换成DataTable
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="isUseNewColumnName">是否使用新列名,默认:是</param>
/// <param name="deleteEndRowIndex">删除上面的行索引(由于有些Excel导入时上面会存在多余行)</param>
/// <returns>返回列名Cols0,Cols1,Cols2···以此类推</returns>
public DataTable ExcelToTable(string filePath, bool isUseNewColumnName = true, int deleteEndRowIndex = 0)
{
DataTable dataTable = new DataTable();
string a = Path.GetExtension(filePath).ToLower();
DataTable result;
using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
IWorkbook workbook;
if (a == ".xlsx")
{
workbook = new XSSFWorkbook(fileStream);
}
else
{
if (a == ".xls")
{
workbook = new HSSFWorkbook(fileStream);
}
else
{
workbook = null;
throw new Exception("请导入.xlsx或.xls格式的文档");
}
}
if (workbook == null)
{
result = null;
return result;
}
ISheet sheetAt = workbook.GetSheetAt(0);
if (deleteEndRowIndex != 0)
{
for (int i = deleteEndRowIndex; i >= 1; i--)
{
sheetAt.ShiftRows(i, i + 1, -1);
}
}
IRow row = sheetAt.GetRow(sheetAt.FirstRowNum);
List<int> list = new List<int>();
for (int i = 0; i < (int)row.LastCellNum; i++)
{
if (isUseNewColumnName)
{
dataTable.Columns.Add(new DataColumn("Cols" + i.ToString()));
}
else
{
object valueType = this.GetValueType(row.GetCell(i));
if (valueType == null || valueType.ToString() == string.Empty)
{
dataTable.Columns.Add(new DataColumn("Cols" + i.ToString()));
}
else
{
dataTable.Columns.Add(new DataColumn(valueType.ToString()));
}
}
list.Add(i);
}
for (int j = sheetAt.FirstRowNum + 1; j <= sheetAt.LastRowNum; j++)
{
DataRow dataRow = dataTable.NewRow();
bool bCellIsNull = false;
foreach (int current in list)
{
if (sheetAt.GetRow(j) == null)
break;
ICell cell = sheetAt.GetRow(j).GetCell(current);
dataRow[current] = this.GetValueType(cell);
if (dataRow[current] != null && dataRow[current].ToString() != string.Empty)
{
bCellIsNull = true;
}
}
if (bCellIsNull)
{
dataTable.Rows.Add(dataRow);
}
}
}
result = dataTable;
return result;
}
/// <summary>
/// 获取单元格类型
/// </summary>
/// <param name="cell"></param>
/// <returns></returns>
private object GetValueType(ICell cell)
{
bool flag = cell == null;
object result;
if (flag)
{
result = null;
}
else
{
switch (cell.CellType)
{
case CellType.Numeric: //数值
result = cell.NumericCellValue;
return result;
case CellType.String: //文本
result = cell.StringCellValue;
return result;
case CellType.Blank: //空值
result = null;
return result;
case CellType.Boolean: //布尔类型
result = cell.BooleanCellValue;
return result;
case CellType.Error: //二进制
result = cell.ErrorCellValue;
return result;
case CellType.Formula: //公式
//这里只能处理数值公式。其他公式将会被转换成数值类型,如:日期公式。
result = cell.NumericCellValue;
return result;
}
result = "=" + cell.CellFormula;
}
return result;
}
#endregion
感谢支持,有写得不好的地方还望多多指教。