目录
概述:NPOI 是一个功能强大的第三方库,支持 .xls 和 .xlsx 格式,且完全开源。NPOI 可以在任何平台上运行,无需安装 Excel。
优点:跨平台,支持 .xls 和 .xlsx 格式,性能较好。
缺点:与原生 Excel 功能兼容性较低,格式化和高级功能支持相对有限。
1. 安装 NPOI
2. 使用 NPOI 创建新 Excel 文件
以下代码演示了如何使用 NPOI 创建一个新的 Excel 文件,并向其中写入 DataTable 数据。
using System.Data;
using System.IO;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel; // 对于 .xlsx 文件
using NPOI.HSSF.UserModel; // 对于 .xls 文件
public void CreateNewExcel(string filePath, DataTable dataTable)
{
IWorkbook workbook;
if (filePath.EndsWith(".xlsx"))
workbook = new XSSFWorkbook(); // 创建 .xlsx 文件
else
workbook = new HSSFWorkbook(); // 创建 .xls 文件
var sheet = workbook.CreateSheet("Sheet1");
// 写入表头
var headerRow = sheet.CreateRow(0);
for (int i = 0; i < dataTable.Columns.Count; i++)
{
headerRow.CreateCell(i).SetCellValue(dataTable.Columns[i].ColumnName);
}
// 写入数据
for (int i = 0; i < dataTable.Rows.Count; i++)
{
var dataRow = sheet.CreateRow(i + 1);
for (int j = 0; j < dataTable.Columns.Count; j++)
{
dataRow.CreateCell(j).SetCellValue(dataTable.Rows[i][j].ToString());
}
}
// 保存文件
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(stream);
}
}
3. 设置列宽和行高
1. 设置列宽
public void SetColumnWidth(IWorkbook workbook, int sheetIndex, int columnIndex)
{
var sheet = workbook.GetSheetAt(sheetIndex);
// 设置列宽(单位是 1/256 字符宽度)
sheet.SetColumnWidth(columnIndex, 20 * 256); // 设置第 1 列宽度为 20
}
2. 设置行高
public void SetColumnRowHeight(IWorkbook workbook, int sheetIndex, int rowIndex)
{
var sheet = workbook.GetSheetAt(sheetIndex);
// 设置行高(单位是点数)
var row = sheet.GetRow(rowIndex) ?? sheet.CreateRow(rowIndex);
row.HeightInPoints = 25; // 设置行高为 25 点
}
3. 同时设置列宽和行高
public void SetColumnWidthAndRowHeight(IWorkbook workbook, int sheetIndex, int columnIndex, int rowIndex)
{
var sheet = workbook.GetSheetAt(sheetIndex);
// 设置列宽(单位是 1/256 字符宽度)
sheet.SetColumnWidth(columnIndex, 20 * 256); // 设置第 1 列宽度为 20
// 设置行高(单位是点数)
var row = sheet.GetRow(rowIndex) ?? sheet.CreateRow(rowIndex);
row.HeightInPoints = 25; // 设置行高为 25 点
}
4. 设置统一的行高
在 NPOI 中,行高是通过每一行对象来设置的。可以遍历所有行并设置它们的行高,也可以在每次创建行时直接设定统一的高度。
public void SetUniformRowHeight(ISheet sheet, float heightInPoints)
{
for (int i = 0; i <= sheet.LastRowNum; i++)
{
var row = sheet.GetRow(i) ?? sheet.CreateRow(i);
row.HeightInPoints = heightInPoints; // 设置行高
}
}
5. 设置统一的列宽
列宽可以直接对整个列进行设置,无需单独遍历单元格。列宽是以 1/256 字符宽度为单位的,设置时需要乘以 256。
public void SetUniformColumnWidth(ISheet sheet, int widthInCharacters)
{
for (int i = 0; i < sheet.GetRow(0).LastCellNum; i++) // 以第一行的单元格数量为列数
{
sheet.SetColumnWidth(i, widthInCharacters * 256); // 设置列宽
}
}
6. 应用统一的行高和列宽
可以将行高和列宽设置封装在一个方法中调用:
public void SetUniformRowHeightAndColumnWidth(ISheet sheet, float rowHeightInPoints, int columnWidthInCharacters)
{
SetUniformRowHeight(sheet, rowHeightInPoints);
SetUniformColumnWidth(sheet, columnWidthInCharacters);
}
使用示例:
假设我们有一个表格 sheet,要将所有行高统一设置为 20 点,列宽统一设置为 15 个字符宽:
SetUniformRowHeightAndColumnWidth(sheet, 20, 15);
这样就能高效地将整个表格的行高和列宽统一设置,无需遍历每个单元格。
4. 合并单元格
合并单元格可以通过 CellRangeAddress 设置,需要定义起始和结束的行列。
using NPOI.SS.Util;
public void MergeCells(IWorkbook workbook, int sheetIndex, int firstRow, int lastRow, int firstCol, int lastCol)
{
var sheet = workbook.GetSheetAt(sheetIndex);
// 合并单元格
var cellRangeAddress = new CellRangeAddress(firstRow, lastRow, firstCol, lastCol);
sheet.AddMergedRegion(cellRangeAddress);
// 可以对合并后的单元格设置样式
var cell = sheet.GetRow(firstRow).GetCell(firstCol) ?? sheet.GetRow(firstRow).CreateCell(firstCol);
var style = workbook.CreateCellStyle();
style.Alignment = HorizontalAlignment.Center;
cell.CellStyle = style;
}
5. 设置单元格样式(字体、边框、背景色等)
使用 ICellStyle 进行字体、对齐、边框、背景等样式的配置:
public void SetCellStyle(IWorkbook workbook, int sheetIndex, int rowIndex, int colIndex)
{
var sheet = workbook.GetSheetAt(sheetIndex);
var cell = sheet.GetRow(rowIndex).GetCell(colIndex) ?? sheet.GetRow(rowIndex).CreateCell(colIndex);
var style = workbook.CreateCellStyle();
// 设置字体
var font = workbook.CreateFont();
font.FontHeightInPoints = 12;
font.FontName = "Arial";
font.IsBold = true;
style.SetFont(font);
// 设置边框
style.BorderBottom = BorderStyle.Thin;
style.BorderLeft = BorderStyle.Thin;
style.BorderRight = BorderStyle.Thin;
style.BorderTop = BorderStyle.Thin;
// 设置背景颜色
style.FillForegroundColor = IndexedColors.LightBlue.Index;
style.FillPattern = FillPattern.SolidForeground;
cell.CellStyle = style;
cell.SetCellValue("示例文本");
}
5. 向现有的 Excel 文件追加数据
追加数据时,可以定位到现有数据的末尾,创建新行并写入。
public void AppendDataToExistingExcel(string filePath, DataTable dataTable)
{
IWorkbook workbook;
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
workbook = filePath.EndsWith(".xlsx") ? (IWorkbook)new XSSFWorkbook(stream) : new HSSFWorkbook(stream);
}
var sheet = workbook.GetSheetAt(0);
int lastRowNum = sheet.LastRowNum;
for (int i = 0; i < dataTable.Rows.Count; i++)
{
var dataRow = sheet.CreateRow(lastRowNum + i + 1);
for (int j = 0; j < dataTable.Columns.Count; j++)
{
dataRow.CreateCell(j).SetCellValue(dataTable.Rows[i][j].ToString());
}
}
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Write))
{
workbook.Write(stream);
}
}
6. 综合操作示例
将所有设置组合在一起,确保不同操作可以在一个文件中同时应用:
public void FullExample(string filePath, DataTable dataTable)
{
IWorkbook workbook = filePath.EndsWith(".xlsx") ? (IWorkbook)new XSSFWorkbook() : new HSSFWorkbook();
var sheet = workbook.CreateSheet("Sheet1");
// 设置表头
var headerRow = sheet.CreateRow(0);
for (int i = 0; i < dataTable.Columns.Count; i++)
{
headerRow.CreateCell(i).SetCellValue(dataTable.Columns[i].ColumnName);
}
// 写入数据
for (int i = 0; i < dataTable.Rows.Count; i++)
{
var dataRow = sheet.CreateRow(i + 1);
for (int j = 0; j < dataTable.Columns.Count; j++)
{
dataRow.CreateCell(j).SetCellValue(dataTable.Rows[i][j].ToString());
}
}
// 设置列宽和行高
SetColumnWidthAndRowHeight(workbook, 0, 1, 1);
// 合并单元格(比如合并第 2 行第 1 列到第 2 列)
MergeCells(workbook, 0, 1, 1, 0, 1);
// 设置单元格样式
SetCellStyle(workbook, 0, 1, 1);
// 保存文件
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write))
{
workbook.Write(stream);
}
}
总结:
- 创建、读取、追加、设置样式等基本操作可以涵盖常见的 NPOI 使用场景。
- NPOI 适合处理数据量较大的 Excel 文件,不依赖于 Excel 安装,并且支持 .xls 和 .xlsx 格式。