轉載來源:https://blog.csdn.net/M1234uy/article/details/107695252
前言
Npoi
可以在沒有安裝Office 的情況寫 對 Word 或 Excel 文檔進行讀寫操作。
npoi 是一個開源
的C#讀寫Excel、Word等微軟OLE2組件文檔的項目。本文主要講對 Excel 文檔進行讀寫操作。
一、讀取 Excel
1-1 讀取 Excel 文件
流程圖
代碼
/// <summary>
/// 讀取IWorkbook
/// </summary>
public IWorkbook ReadWorkbook = null;
/// <summary>
/// 獲取讀取 WorkBook
/// </summary>
public void GetReadWorkbook(string FilePath)
{
// 獲取擴展名
string ExtensionName = System.IO.Path.GetExtension(FilePath);
// 文件流
FileStream FileStream = new FileStream(FilePath, FileMode.Open, FileAccess.ReadWrite);
// 把xls寫入workbook中 2003版本
if (ExtensionName.Equals(".xls"))
{
ReadWorkbook = new HSSFWorkbook(FileStream);
}
// 把xlsx 寫入workbook中 2007版本
else if (ExtensionName.Equals(".xlsx"))
{
ReadWorkbook = new XSSFWorkbook(FileStream);
}
else
{
ReadWorkbook = null;
}
FileStream.Close();
}
1-2 讀取 Sheet
1-2-1 獲取所有 Sheet
通過 For 循環 Workbook,獲取所有 Sheet。
/// <summary>
/// 獲取表中的Sheet名稱
/// </summary>
public List<ISheet> Sheets = null;
/// <summary>
/// 獲取所有 Sheet表
/// </summary>
public void GetSheets()
{
// 獲取表
Sheets = new List<ISheet>();
var SheetCount = ReadWorkbook.NumberOfSheets;
for (int i = 0; i < SheetCount; i++)
{
Sheets.Add(ReadWorkbook.GetSheetAt(i));
}
}
1-2-2 獲取單個Sheet
通過 Sheet名 獲取Sheet有兩種方法:
1. 通過 SheetName 獲取 Sheet。
// 1. 通過Sheet 名獲取 Sheet
int sheetIndex =ReadWorkbook.GetSheet("SheetName")
- 1
- 2
2. 通過 SheetName 獲取 Sheet數組對應的 下標。 再通過Sheet下標獲取Sheet。
// 2.a通過Sheet 名獲取 Sheet數組對應的下標;
int sheetIndex =ReadWorkbook.GetSheetIndex("SheetName")
// 2.b 通過 Sheet下標獲取 對應的 Sheet 數據
Isheet sheet =ReadWorkbook.GetSheetAt(sheetIndex )
1-3 讀取 Sheet 數據
流程圖
代碼
/// <summary>
/// 獲取 Sheet 表數據
/// </summary>
/// <param name="Sheet"></param>
private void GetSheetData(ISheet Sheet)
{
if (Sheet == default)
{
return null;
}
IRow row;
// 1. 獲取行數
var rowCount = Sheet.LastRowNum;
// 從第四行(下標爲3)開始獲取數據,前三行是表頭
// 如果從第一行開始,則i=0就可以了
for (int i = 3; i <= rowCount; i++)
{
var dataTable = new DataTable_Model();
// 獲取具體行
row = Sheet.GetRow(i);
if (row != null)
{
// 2. 獲取行對應的列數
var column = row.LastCellNum;
for (int j = 0; j < column; j++)
{
// 3. 獲取某行某列對應的單元格數據
var cellValue = row.GetCell(j).ToString();
// 4. 輸出單元格數據
Console.Wlite(cellValue+" ");
}
// 換行
Console.WliteLine();
}
}
}
二、修改 Excel
2-1 修改單元格數據
流程圖
代碼
/// <summary>
/// 修改 Field Sheet
/// </summary>
/// <param name="SheetName"></param>
/// <returns></returns>
private void UpdateSheet(string SheetName, string FilePath)
{
// 創建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通過Sheet名 獲取對應的ISeet--其中 ReadWorkbook 爲讀取Excel文檔時獲取
var sheet = ReadWorkbook.GetSheet(SheetName);
// 2. 獲取行數
int rowCount = sheet.LastRowNum;
for (int i = 0; i < rowCount; i++)
{
// 3. 獲取行對應的列數
int columnount = sheet.GetRow(i).LastCellNum;
for (int j = 0; j < columnount; j++)
{
// 4. 獲取某行某列對應的單元格數據
// 其中前三行設計爲表頭,故i+3,這裏可以自己定義
var sheetCellValue = sheet.GetRow(i + 3).GetCell(j);
// 5. 向單元格傳值,以覆蓋對應的單元格數據
sheetCellValue.SetCellValue(sheetCellValue + "Update");
}
}
// 6. 對 Workbook 的修改寫入文件流,對文件進行相應操作
ReadWorkbook.Write(fsWrite);
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 7. 關閉文件流:報不報錯都關閉
fsWrite.Close();
}
}
2-2 修改指定行數據
流程圖
代碼
/// <summary>
/// 修改 Field Sheet
/// </summary>
/// <param name="SheetName"></param>
/// <returns></returns>
private void UpdateSheet(string SheetName, string FilePath,int RowCount)
{
// 創建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通過Sheet名 獲取對應的ISeet--其中 ReadWorkbook 爲讀取Excel文檔時獲取
var sheet = ReadWorkbook.GetSheet(SheetName);
// 2. 獲取行對應的列數
int column = sheet.GetRow(RowCount).LastCellNum;
for (int j = 0; j < column ; j++)
{
// 3. 獲取某行某列對應的單元格數據
// 其中前三行設計爲表頭,故i+3,這裏可以自己定義
var sheetCellValue = sheet.GetRow(RowCount).GetCell(j);
// 4. 向單元格傳值,以覆蓋對應的單元格數據
sheetCellValue.SetCellValue(sheetCellValue + "Update");
}
// 5. 對 Workbook 的修改寫入文件流,對文件進行相應操作
ReadWorkbook.Write(fsWrite);
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 7. 關閉文件流:報不報錯都關閉
fsWrite.Close();
}
}
三、刪除 Excel
3-1 刪除 Sheet 表
流程圖
代碼
/// <summary>
/// 刪除其中一個Sheet
/// Bug:刪除後,無Sheet表存在BUG
/// </summary>
/// <param name="SheetName"></param>
/// <param name="FilePath"></param>
/// <returns></returns>
public bool RemoveOneSheet(string SheetName, string FilePath)
{
var Result = false;
// 創建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通過Sheet名字查找Sheet下標
var sheetIndex = ReadWorkbook.GetSheetIndex(SheetName);
if (sheetIndex >= 0)
{
// 2. 通過Sheet下標移除 Sheet
ReadWorkbook.RemoveSheetAt(sheetIndex);
// 3. 對 Workbook 的修改寫入文件流,對文件進行相應操作
ReadWorkbook.Write(fsWrite);
Result = true;
}
return Result;
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 4. 關閉文件流:報不報錯都關閉
fsWrite.Close();
}
}
【注意】:若Excel 表格刪除後 沒有Sheet表格
,打開Excel時會出現錯誤。
【參考解決思路】:刪除指定Sheet表格後,判斷Excel中是否存在Sheet表,若存在則寫入Excel表格;反之,刪除該Excel文件。(僅供參考)
3-2 清空 Sheet 表指定行數據
只清空數據,不刪除改行( 該方法存在BUG,暫時無法使用。)
流程圖
代碼
/// <summary>
/// 清空 Sheet指定行數據
/// </summary>
/// <param name="Row"></param>
/// <param name="SheetName"></param>
/// <param name="FilePath"></param>
/// <returns></returns>
public bool EmptySheetRow(int RowNum, string SheetName, string FilePath)
{
var Result = false;
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
1. 通過Sheet名 獲取對應的 ISheet
ISheet sheet_Table = ReadWorkbook.GetSheet(SheetName);
if (sheet_Table != null)
{
// 2. 定位到要刪除的指定行
IRow row = sheet_Table.GetRow(RowNum - 1);
if (row != null)
{
// 3. 清空行數據
sheet_Table.RemoveRow(row);
// 4. 對 Workbook 的修改寫入文件流,對文件進行相應操作;
ReadWorkbook.Write(fsWrite);
Result = true;
}
}
else
{
new Exception("This the Sheet does not exist");
}
return Result;
}
catch (Exception ex)
{
throw ex;
}
finally
{
fsWrite.Close();
}
}
3-3 刪除 Sheet 表指定行
Sheet 不提供 直接刪除行的數據,這裏利用上下移動的方法,刪除指定行。
向上移動行過程
流程圖
代碼
/// <summary>
/// 刪除 Sheet指定行數據
/// </summary>
/// <param name="StartNum">起始行</param>
/// <param name="EndNum">終止行</param>
/// <param name="SheetName"></param>
/// <param name="FilePath"></param>
/// <returns></returns>
public bool RemoveSheetRow(int StartNum, int EndNum, string SheetName, string FilePath)
{
var Result = false;
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通過Sheet名 獲取對應的ISheet
ISheet sheetTable = ReadWorkbook.GetSheet(SheetName);
if (sheetTable == null)
{
new Exception("This the Sheet does not exist");
}
// 2. 確定移動行數:保證EndNum >= StartNum
int moveNum = EndNum - StartNum;
// 3. 向上移動moveNum 行
for (int i = 0; i <= moveNum; i++)
{
// 向上移動:第EndNum+1到第sheetTable.LastRowNum+1行向上(-n)移動n行,-n只能爲-1
sheetTable.ShiftRows(EndNum, sheetTable.LastRowNum, -1);
// 循環一次則向上移動一次,移動後需要開始移動的行數-1,則需要EndNum -1。不理解的話參考上方圖片
EndNum -= 1;
}
//向打開的這個xls文件中寫入數據
ReadWorkbook.Write(fsWrite);
Result = true;
return Result;
}
catch (Exception ex)
{
throw ex;
}
finally
{
fsWrite.Close();
}
}
四、寫入 Excel
4-1 創建 WorkBook
流程圖
代碼
/// <summary>
/// 寫入IWorkbook
/// </summary>
public IWorkbook WriteWorkbook = null;
/// <summary>
/// 獲取寫入WorkBook
/// </summary>
public void GetWriteWorkbook(string FilePath)
{
// 獲取擴展名
string ExtensionName = System.IO.Path.GetExtension(FilePath);
// 把xls寫入workbook中 2003版本
if (ExtensionName.Equals(".xls"))
{
WriteWorkbook = new HSSFWorkbook();
}
// 把xlsx 寫入workbook中 2007版本
else if (ExtensionName.Equals(".xlsx"))
{
WriteWorkbook = new XSSFWorkbook();
}
else
{
WriteWorkbook = null;
}
}
4-2 寫入 Excel 文件
流程圖
代碼
/// <summary>
/// Table 實體類數據轉 表格數據
/// </summary>
/// <param name="FilePath"></param>
/// <returns></returns>
private void TableDataToCell(string FilePath)
{
FileStream fsWrite = new FileStream(FilePath, FileMode.Create, FileAccess.Write);
try
{
// 1. 在WriteWorkbook 上添加名爲 SheetTest 的數據表
ISheet sheet=WriteWorkbook.CreateSheet("SheetTest ");
// 2. 定義行數
var rowCount = 6;
// 3. 定義列數
int columnount = 8;
for (int i = 0; i < rowCount; i++)
{
// 4. 創建行
IRow row = sheet.CreateRow(i);
for (int j = 0; j < columnount; j++)
{
// 5. 創建某行某列對應的單元格
ICell cell = row.CreateCell(j);
// 6. 向單元格添加值
cell.SetCellValue($"第{i}行 第{j}列");
// 添加表格樣式
cell.CellStyle = ExpandFliePath.OtherRowStyle();
}
}
//7. 將表單寫入文件流
WriteWorkbook.Write(fsWrite);
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 關閉文件流
fsWrite.Close();
}
}
五、單元格樣式
定義樣式,這裏定義的樣式比較簡單。
單元格樣式在創建或獲取到單元格時 , cell.CellStyle =OtherRowStyle();
可以獲取該樣式。
/// <summary>
/// 樣式
/// </summary>
/// <returns></returns>
public static ICellStyle OtherRowStyle()
{
var workbook = WriteWorkbook;
ICellStyle cellStyle = workbook.CreateCellStyle();
IFont font = workbook.CreateFont();
font.FontName = "微軟雅黑";
//font.FontHeightInPoints = 15;
設置字體加粗樣式
//font.IsBold = true;
// 使用SetFont方法將字體樣式添加到單元格樣式中
cellStyle.SetFont(font);
// 單元格樣式:水平對齊居中
cellStyle.Alignment = HorizontalAlignment.Center;
//邊框
cellStyle.BorderBottom = BorderStyle.Thin;
cellStyle.BorderLeft = BorderStyle.Thin;
cellStyle.BorderRight = BorderStyle.Thin;
cellStyle.BorderTop = BorderStyle.Thin;
// 自動換行
cellStyle.WrapText = true;
背景色
//cellStyle.FillForegroundColor = BlueGrey.Index;
return cellStyle;
}