目錄
- 前言
- NPOI
- 測驗
- 小結
前言
時間過得好快,在之前升級到3.0之后,就感覺好久沒再動過啥東西了,之前有問到Swagger的中文漢化,雖說我覺得這種操作的意義不是太大,也是多少鼓搗了下,其實個人感覺就是元素內容替換,既然可以執行js了那不就是網頁上隨便搞了,所以就沒往下再折騰,但是現在需要用到Excel的操作了,那就不得不提起這個NPOI了,
NPOI
在之前.net framework的時候,工程需要用到Excel的匯入匯出,當然用這個NPOI是偶然,也就是找了下這個看著可以就用了,之后遇到的各種問題也都找資料解決,什么多行合并啊,打開2007版本錯誤啊之類的,但是不得不說,用著還挺好,所以既然net core需要了,那就看看唄,剛好也是支持的,
在Util我們來引入這個類別庫NPOI,

- 匯入
在使用之前,我們先縷一下獲取Excel資料需要哪些準備操作,
- 獲取檔案(這個就不多說)
- 獲取sheet資訊(考慮有可能多sheet操作)
- 根據sheet獲取對應檔案資訊(多少行,當然有些還有合并)
- 根據合并行來判斷第一行是否為標題
- 判斷哪一行是列名(用于對應資料)
- 遍歷每一行并根據每一行的資料格式來獲取(有可能是公式/日期/數字/普通文本等等)
ok,大致上清楚了之后,我們就一步步來看吧,這里我創建一個ExcelUtil,來寫第一個方法(這里只做說明展示吧),
public class ExcelUtil
{
/// <summary>
/// 讀取Excel多Sheet資料
/// </summary>
/// <param name="filePath">檔案路徑</param>
/// <param name="sheetName">Sheet名</param>
/// <returns></returns>
public static DataSet ReadExcelToDataSet(string filePath, string sheetName = null)
{
if (!File.Exists(filePath))
{
LogUtil.Debug($"未找到檔案{filePath}");
return null;
}
//獲取檔案資訊
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
IWorkbook workbook = WorkbookFactory.Create(fs);
//獲取sheet資訊
ISheet sheet = null;
DataSet ds = new DataSet();
if (!string.IsNullOrEmpty(sheetName))
{
sheet = workbook.GetSheet(sheetName);
if (sheet == null)
{
LogUtil.Debug($"{filePath}未找到sheet:{sheetName}");
return null;
}
DataTable dt = ReadExcelFunc(workbook, sheet);
ds.Tables.Add(dt);
}
else
{
//遍歷獲取所有資料
int sheetCount = workbook.NumberOfSheets;
for (int i = 0; i < sheetCount; i++) {
sheet = workbook.GetSheetAt(i);
if (sheet != null)
{
DataTable dt = ReadExcelFunc(workbook, sheet);
ds.Tables.Add(dt);
}
}
}
return ds;
}
/// <summary>
/// 讀取Excel資訊
/// </summary>
/// <param name="workbook">作業區</param>
/// <param name="sheet">sheet</param>
/// <returns></returns>
private static DataTable ReadExcelFunc(IWorkbook workbook, ISheet sheet)
{
DataTable dt = new DataTable();
//獲取列資訊
IRow cells = sheet.GetRow(sheet.FirstRowNum);
int cellsCount = cells.PhysicalNumberOfCells;
int emptyCount = 0;
int cellIndex = sheet.FirstRowNum;
List<string> listColumns = new List<string>();
bool isFindColumn = false;
while (!isFindColumn)
{
emptyCount = 0;
listColumns.Clear();
for (int i = 0; i < cellsCount; i++)
{
if (string.IsNullOrEmpty(cells.GetCell(i).StringCellValue))
{
emptyCount++;
}
listColumns.Add(cells.GetCell(i).StringCellValue);
}
//這里根據邏輯需要,空列超過多少判斷
if (emptyCount == 0)
{
isFindColumn = true;
}
cellIndex++;
cells = sheet.GetRow(cellIndex);
}
foreach (string columnName in listColumns)
{
if (dt.Columns.Contains(columnName))
{
//如果允許有重復列名,自己做處理
continue;
}
dt.Columns.Add(columnName, typeof(string));
}
//開始獲取資料
int rowsCount = sheet.PhysicalNumberOfRows;
cellIndex += 1;
DataRow dr = null;
for (int i = cellIndex; i < rowsCount; i++) {
cells = sheet.GetRow(i);
dr = dt.NewRow();
for (int j = 0; j < dt.Columns.Count; j++)
{
//這里可以判斷資料型別
switch (cells.GetCell(j).CellType)
{
case CellType.String:
dr[j] = cells.GetCell(j).StringCellValue;
break;
case CellType.Numeric:
dr[j] = cells.GetCell(j).NumericCellValue.ToString();
break;
case CellType.Unknown:
dr[j] = cells.GetCell(j).StringCellValue;
break;
}
}
dt.Rows.Add(dr);
}
return dt;
}
}
檔案的匯入操作就不再演示了,之前有檔案上傳的相關操作方法net core WebApi——檔案分片上傳與跨域請求處理,
匯入的處理這里也只是大致演示下,具體需要的東西包括情況可能會比較復雜,但是終歸資料還是那些,只是操作方法不同罷了(別說什么騷操作),
- 匯出
相對于匯入,匯出的流程就比較簡單了,
- 獲取資料資訊(sql或檔案)
- 組成資料集合(List或DataTable)
- 創建sheet
- 設定相關樣式等等
- 遍歷賦值row
- 匯出檔案流
了解完,我們就繼續來搞吧,
/// <summary>
/// 匯出Excel檔案
/// </summary>
/// <typeparam name="T">資料型別</typeparam>
/// <param name="entities">資料物體</param>
/// <param name="dicColumns">列對應關系,如Name->姓名</param>
/// <param name="title">標題</param>
/// <returns></returns>
public static byte[] ExportExcel<T>(List<T> entities,Dictionary<string,string> dicColumns, string title = null)
{
if (entities.Count <= 0)
{
return null;
}
//HSSFWorkbook => xls
//XSSFWorkbook => xlsx
IWorkbook workbook = new XSSFWorkbook();
ISheet sheet = workbook.CreateSheet("test");//名稱自定義
IRow cellsColumn = null;
IRow cellsData = https://www.cnblogs.com/AprilBlank/p/null;
//獲取物體屬性名
PropertyInfo[] properties = entities[0].GetType().GetProperties();
int cellsIndex = 0;
//標題
if (!string.IsNullOrEmpty(title))
{
ICellStyle style = workbook.CreateCellStyle();
//邊框
style.BorderBottom = BorderStyle.Dotted;
style.BorderLeft = BorderStyle.Hair;
style.BorderRight = BorderStyle.Hair;
style.BorderTop = BorderStyle.Dotted;
//水平對齊
style.Alignment = HorizontalAlignment.Left;
//垂直對齊
style.VerticalAlignment = VerticalAlignment.Center;
//設定字體
IFont font = workbook.CreateFont();
font.FontHeightInPoints = 10;
font.FontName ="微軟雅黑";
style.SetFont(font);
IRow cellsTitle = sheet.CreateRow(0);
cellsTitle.CreateCell(0).SetCellValue(title);
cellsTitle.RowStyle = style;
//合并單元格
sheet.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 1, 0, dicColumns.Count - 1));
cellsIndex = 2;
}
//列名
cellsColumn = sheet.CreateRow(cellsIndex);
int index = 0;
Dictionary<string, int> columns = new Dictionary<string, int>();
foreach (var item in dicColumns)
{
cellsColumn.CreateCell(index).SetCellValue(item.Value);
columns.Add(item.Value, index);
index++;
}
cellsIndex += 1;
//資料
foreach (var item in entities)
{
cellsData = https://www.cnblogs.com/AprilBlank/p/sheet.CreateRow(cellsIndex);
for (int i = 0; i < properties.Length; i++)
{
if (!dicColumns.ContainsKey(properties[i].Name)) continue;
//這里可以也根據資料型別做不同的賦值,也可以根據不同的格式參考上面的ICellStyle設定不同的樣式
object[] entityValues = new object[properties.Length];
entityValues[i] = properties[i].GetValue(item);
//獲取對應列下標
index = columns[dicColumns[properties[i].Name]];
cellsData.CreateCell(index).SetCellValue(entityValues[i].ToString());
}
cellsIndex++;
}
byte[] buffer = null;
using (MemoryStream ms = new MemoryStream())
{
workbook.Write(ms);
buffer = ms.GetBuffer();
ms.Close();
}
return buffer;
}
測驗
寫完,免不了一通測驗,這里不多說了,直接上圖,
匯入這里前面也說了沒做界面上傳什么的,就是一個檔案路徑,直接執行,Excel原檔案我也會同步上傳到代碼倉庫,

匯出的話,這里也是用Swagger神器來測驗,

資料庫資料如下圖,


帶標題匯出,

小結
最近真的是有點兒忙,一直在鼓搗opengl這類圖形化的東西,各種矩陣轉換模型轉換,要么是用c++,qt寫opengl,要么是用threejs搞opengl,唉,整的最近也只能是晚上回去摸索會兒net core,作業總是不那么盡如人意,但是身為程式猿的我們,不都是不斷的摸索前進么?我們可以不會,但那不是我們不整的借口,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/105846.html
標籤:.NET Core
