C#使用NPOI库操作Excel
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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)