C#使用NPOI庫操作Excel
https://www.cnblogs.com/restran/p/3889479.html
https://www.cnblogs.com/wanzhongjun/p/7151514.html
https://blog.csdn.net/WuLex/article/details/108914907
https://www.pianshen.com/article/9409729801/
1. 引用動態庫
ICSharpCode.SharpZipLib.dll
NPOI.dll
NPOI.OOXML.dll
NPOI.OpenXml4Net.dll
NPOI.OpenXmlFormats.dll
2. 頭文件
using NPOI;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
using NPOI.HSSF.UserModel;
using System.Diagnostics;
3. 從Excel中讀取
excel表格有兩種后綴名 .xls 和 .xlsx。.xls是office2007以前版本的excel表的后綴名,而.xlsx是office2007以后的excel后綴。
一個excel文件表里有多個工作簿sheet,每一個工作簿中都可以存數據。
(1)打開.xlsx文件
//打開或創建excel文件並向里添加數據
//new HSSFWorkbook(); //這是用於后綴名是.xls的excel文件的操作
FileStream fs = File.OpenRead("C:\\Users\\Administrator\\Desktop\\table1.xlsx"); //關聯流打開文件
IWorkbook workbook = null;
workbook = new XSSFWorkbook(fs); //XSSF打開xlsx
(2)讀取sheet
ISheet sheet = null;
sheet = workbook.GetSheetAt(i); //獲取第i個sheet
(3)讀取行
IRow row = null;
row = sheet.GetRow(i); //獲取第i行
//行標從0開始計數
int numsOfRows = sheet.LastRowNum + 1; //sheet.LastRowNum為最后一行的index
(4)讀取某行的單元格內的數據(單元格內可存不同數據類型)
ICell cell = row.GetCell(i); //獲取row行的第i列的數據
//單元格存儲的數據類型
public enum CellType
{
Unknown = -1,
Numeric = 0,
String = 1,
Formula = 2,
Blank = 3,
Boolean = 4,
Error = 5
}
//NPOI庫中ICell定義
public interface ICell
{
ISheet Sheet { get; }
CellRangeAddress ArrayFormulaRange { get; }
IHyperlink Hyperlink { get; set; }
IComment CellComment { get; set; }
ICellStyle CellStyle { get; set; }
bool BooleanCellValue { get; }
string StringCellValue { get; } //若存儲的是string,可通過該屬性獲取string值
byte ErrorCellValue { get; }
IRichTextString RichStringCellValue { get; }
DateTime DateCellValue { get; } //獲取DateTime
double NumericCellValue { get; }
string CellFormula { get; set; }
CellType CachedFormulaResultType { get; }
CellType CellType { get; } //通過該屬性獲取存儲的數據的類型
IRow Row { get; }
bool IsMergedCell { get; }
int RowIndex { get; }
int ColumnIndex { get; }
bool IsPartOfArrayFormulaGroup { get; }
ICell CopyCellTo(int targetIndex);
CellType GetCachedFormulaResultTypeEnum();
void RemoveCellComment();
void RemoveHyperlink();
void SetAsActiveCell();
void SetCellErrorValue(byte value);
void SetCellFormula(string formula);
void SetCellType(CellType cellType);
void SetCellValue(bool value);
void SetCellValue(string value);
void SetCellValue(IRichTextString value);
void SetCellValue(DateTime value);
void SetCellValue(double value);
}
- 據此,可自定義一個根據數據類型獲取數據的函數:
//返回值是object,具體用變量來接的時候,要先強轉一下
/**
在讀取文件時大都會判斷單元格類型,方式大同小異,只有日期類型不同。
默認日期類型的單元格在NPOI都認為是數值類型(CellType.Numeric)
在高版本中用HSSFDateUtil.IsCellDateFormatted(cell) 來判斷
但在低版中沒有這個類,網上找到有NPOI.SS.UserModel.DateUtil.IsCellDateFormatted(cell),同樣的作用。
*/
public object GetCellValue(ICell cell)
{
object value = null;
try
{
if (cell.CellType != CellType.Blank)
{
switch (cell.CellType)
{
case CellType.Numeric:
//判斷單元格內數據是否是DateTime
if (DateUtil.IsCellDateFormatted(cell))
{
value = cell.DateCellValue; //若是日期格式,則用DateCellValue獲取DateTime
}
else
{
// Numeric type
value = cell.NumericCellValue;
}
break;
case CellType.Boolean:
// Boolean type
value = cell.BooleanCellValue;
break;
case CellType.Formula:
value = cell.CellFormula;
break;
default:
// String type
value = cell.StringCellValue;
break;
}
}
}
catch (Exception)
{
value = "";
}
return value;
}
5. 寫Excel
(1)用流創建或讀取.xlsx文件(同時流關聯了文件)
FileStream filestream = new FileStream(@"C:\Users\25224\Desktop\table2.xlsx", FileMode.OpenOrCreate);
//Excel表打開方式public enum FileMode { // // 摘要: // 指定操作系統應創建新文件。這需要 System.Security.Permissions.FileIOPermissionAccess.Write 權限。如果文件已存在,則將引發 // System.IO.IOException異常。 CreateNew = 1, // // 摘要: // 指定操作系統應創建新文件。如果文件已存在,它將被覆蓋。 //這需要 System.Security.Permissions.FileIOPermissionAccess.Write // 權限。FileMode.Create 等效於這樣的請求:如果文件不存在,則使用 System.IO.FileMode.CreateNew;否則使用 System.IO.FileMode.Truncate。如果該文件已存在但為隱藏文件,則將引發 // System.UnauthorizedAccessException異常。 Create = 2, // // 摘要: // 指定操作系統應打開現有文件。 //打開文件的能力取決於 System.IO.FileAccess 枚舉所指定的值。如果文件不存在,引發一個 System.IO.FileNotFoundException // 異常。 Open = 3, // // 摘要: // 指定操作系統應打開文件(如果文件存在);否則,應創建新文件。 //如果用 FileAccess.Read 打開文件,則需要 System.Security.Permissions.FileIOPermissionAccess.Read權限。如果文件訪問為 // FileAccess.Write,則需要 System.Security.Permissions.FileIOPermissionAccess.Write權限。如果用 // FileAccess.ReadWrite 打開文件,則同時需要 System.Security.Permissions.FileIOPermissionAccess.Read // 和 System.Security.Permissions.FileIOPermissionAccess.Write權限。 OpenOrCreate = 4, // // 摘要: // 指定操作系統應打開現有文件。該文件被打開時,將被截斷為零字節大小。這需要 System.Security.Permissions.FileIOPermissionAccess.Write // 權限。嘗試從使用 FileMode.Truncate 打開的文件中進行讀取將導致 System.ArgumentException 異常。 Truncate = 5, // // 摘要: // 若存在文件,則打開該文件並查找到文件尾,或者創建一個新文件。這需要 System.Security.Permissions.FileIOPermissionAccess.Append // 權限。FileMode.Append 只能與 FileAccess.Write 一起使用。試圖查找文件尾之前的位置時會引發 System.IO.IOException // 異常,並且任何試圖讀取的操作都會失敗並引發 System.NotSupportedException 異常。 Append = 6 }
(2)創建表和sheet
XSSFWorkbook wk = new XSSFWorkbook(); //創建表對象wkISheet isheet = wk.CreateSheet("Sheet1"); //在wk中創建sheet1
(3)設置列寬、行高
SetColumnWidth(isheet, 0, 20); //colIndex=0SetColumnWidth(isheet, 1, 20); //colIndex=1IRow row2 =null;row2 = isheet.CreateRow(j);row2.Height =2 * 256;
(4)向單元格中寫數據
IRow row2 =null; ICell cell = null; row2 = isheet.CreateRow(j); //創建index=j的行 cell = row2.CreateCell(0); //在index=j的行中創建index=0的單元格 cell.SetCellValue("哈哈"); //給創建的單元格賦值string
(5)通過流將表中寫入的數據一次性寫入文件中
wk.Write(filestream); //通過流filestream將表wk寫入文件filestream.Close(); //關閉文件流filestreamwk.Close(); //關閉Excel表對象wk
(6)追加數據,保留原有數據
向已存在的Excel追加數據,保留原有數據
/// <summary> /// 向已存在的excel追加數據 /// </summary> /// <param name="excelPath">已存在的excel路徑</param> /// <param name="rowIndex">追加行索引</param> /// <param name="cellData">追加列索引<列索引,單元格值></param> public void addExcelData(string excelPath, int rowIndex, IDictionary<int, string> cellData) { FileStream fs = new FileStream(excelPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);//讀取流 POIFSFileSystem ps = new POIFSFileSystem(fs);//需using NPOI.POIFS.FileSystem; HSSFWorkbook workbook = new HSSFWorkbook(ps); ISheet sheet = workbook.GetSheetAt(0);//獲取工作表 //設置列寬 SetColumnWidth(sheet, 0, 20); SetColumnWidth(sheet, 1, 10); IRow row = sheet.GetRow(rowIndex); //得到表頭 //設置行高 row.Height =2 * 256; ICell cell = null; ICellStyle style = null; foreach (KeyValuePair<int, string> keyValue in cellData) { if (keyValue.Key == 1) { cell = row.CreateCell(keyValue.Key); cell.SetCellValue(keyValue.Value); style = workbook.CreateCellStyle(); //設置左對齊 style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.LEFT; //設置斜線 style.BorderDiagonal = BorderDiagonal.BACKWARD; style.BorderDiagonalLineStyle = NPOI.SS.UserModel.BorderStyle.THIN; //設置換行(若要單元格內換行必須加下面一句) style.WrapText = true; cell.CellStyle = style; } else { cell = row.CreateCell(keyValue.Key); cell.SetCellValue(keyValue.Value); //設置居中 style = workbook.CreateCellStyle(); style.VerticalAlignment = VerticalAlignment.CENTER; style.Alignment = NPOI.SS.UserModel.HorizontalAlignment.CENTER; cell.CellStyle = style; } } FileStream fout = new FileStream(excelPath, FileMode.Open, FileAccess.Write, FileShare.ReadWrite);//寫入流 fout.Flush(); workbook.Write(fout);//寫入文件 workbook = null; fout.Close(); }
6. 日期格式
在Excel表中寫入時間數據時,設置單元格格式,自定義格式yyyy-MM-dd HH:mm:ss
(1)DateTime
.toString("yyyy-MM-dd HH:mm:ss.fff"); //mm-dd才顯示08-01,否則顯示8-1//fff個數表示小數點后顯示的位數,這里精確到小數點后3位
注意:一定要注意大小寫!!!M是月份,寫成了m就是分鍾數了!!
(2)DateTime轉String
DateTime轉string:https://www.cnblogs.com/JiYF/p/7831547.html
(3)String轉DateTime
string轉DateTime:https://www.cnblogs.com/Pickuper/articles/2058880.html