简介
操作指南
某些API参考
视频讲解
完整代码
1、简介
- NPOI是源于一个用于读取xls,doc,ppt文档的POI 项目,POI是Java项目,后面因为有.Net的市场,于是将POI移植到.Net上。
- Npoi 可以在没有安装Office 的情况写 对 Word 或 Excel 文档进行读写操作。另外一种方法是使用.NET自带的excel API,但是这种方法需要运行环境安装微软的excel才行。
- NPOI尤其适合在服务器端生成数据文件!因为服务器一般是不安装office这么庞大的办公软件的
2、名词介绍
- 整个Excel:工作簿
- Sheet页:页签,一个工作簿中可以包含多个Sheet页
- 表格: 对应一个Sheet
- 行、列、单元格
3、C#中的常规操作:
- 导出一个Excel:其实就是要生成一个Excel文件,Excel文件对应的文件流
- 导入一个Excel:读取一个文件,读取文件流,需要从文件流中读取我们需要的各种数据,解析Excel的数据
4、安装
5、细节
- 里面的行列都是从0开始计数的,也即第一行和第一列都是0(但是表格中写的是1开始)
- 注意操作每个步骤的时候要创建、写入、然后关闭文件流
生成
主函数
private void creatBut_Click(object sender, EventArgs e)
{
IWorkbook workbook = ExcelOperationHelper.CreateExcelWorkbook();
FileStream file = new FileStream("E:\\StudyData_ele\\testnew\\NPOI\\Test.xls", FileMode.Create);
workbook.Write(file);
file.Close();
}
类库
/// <summary>
/// 创建一个ExcelWorkbook
/// </summary>
/// <returns></returns>
public static IWorkbook CreateExcelWorkbook()
{
HSSFWorkbook _Workbook = new HSSFWorkbook();
ISheet sheet1 = _Workbook.CreateSheet("Sheet1");
//创建第一行
{
IRow Row0 = sheet1.CreateRow(0);
MessageBox.Show("row:" + Row0);
ICell cell = Row0.CreateCell(0);
cell.SetCellValue("姓名");
ICell cel2 = Row0.CreateCell(1);
cel2.SetCellValue("成绩");
}
//创建第二行
{
IRow Row1 = sheet1.CreateRow(1);
ICell cell = Row1.CreateCell(0);
cell.SetCellValue("王刚");
ICell cel2 = Row1.CreateCell(1);
cel2.SetCellValue("70");
}
return _Workbook;
}
获取数据
读取Excel
//读取 Excel 文件
public IWorkbook ReadWorkbook = null;
public string FilePath = "E:\\StudyData_ele\\testnew\\NPOI\\Test.xls";//输错地址会报错
private void read_Click(object sender, EventArgs e)
{
// 获取扩展名
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();
}
读取sheet
//获取 Sheet
public List<ISheet> Sheets = null;
ISheet sheet1;
ISheet sheet2;
private void button1_Click(object sender, EventArgs e)
{
// 获取所有sheet
Sheets = new List<ISheet>();
var SheetCount = ReadWorkbook.NumberOfSheets;
for (int i = 0; i < SheetCount; i++)
{
Sheets.Add(ReadWorkbook.GetSheetAt(i));
}
//获取单个sheet
//1、通过sheetName获取sheet
sheet1 = ReadWorkbook.GetSheet("Sheet1");
// 2、a通过Sheet 名获取 Sheet数组对应的下标;
int sheetIndex = ReadWorkbook.GetSheetIndex("光照度");
// b 通过 Sheet下标获取 对应的 Sheet 数据
sheet2 = ReadWorkbook.GetSheetAt(sheetIndex);
}
读取sheet数据
//读取 Sheet 数据
private void button2_Click(object sender, EventArgs e)
{
if (Sheets == default)
{
return ;
}
IRow row;
// 1. 获取行数
var rowCount = sheet1.LastRowNum;
//因为Excel表中是从1开始的,而这个是从0开始的,所以行数比Excel中的行数值少1
log.SaveLog("rowCount:" + rowCount);
// 从第2行(下标为1)开始获取数据,第一行是表头
// 如果从第一行开始,则i=0就可以了
for (int i = 1; i <= rowCount; i++)
{
//var dataTable = new DataTable_Model();
// 获取具体行
row = sheet1.GetRow(i);
//都打印了这个row:NPOI.HSSF.UserModel.HSSFRow
log.SaveLog("row:"+row);
if (row != null)
{
// 2. 获取行对应的列数
var column = row.LastCellNum;
//计数到最后出现数据的那一列
log.SaveLog("column:" + column);
for (int j = 0; j < column; j++)
{
// 3. 获取某行某列对应的单元格数据
var cellValue = row.GetCell(j).ToString();
// 4. 输出单元格数据
log.SaveLog(cellValue + " ");
}
}
}
}
写入数据
修改某个数据
使用该方法,xls可以正常使用,但是xlsx不知道怎么使用玩了无法打开,但是确实可以更改了,因为我再点击插入图片就可以了。不知道为什么,但是另存为就不会出问题。可以打开
//修改单元格数据
private void button3_Click(object sender, EventArgs e)
{
// 创建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通过Sheet名 获取对应的ISeet--其中 ReadWorkbook 为读取Excel文档时获取
var sheet = ReadWorkbook.GetSheet("光照度");
// 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+1,从第二行开始,这里可以自己定义
var sheetCellValue = sheet.GetRow(i + 1).GetCell(j);
if (sheetCellValue == null)
{
//创建第一行
{
IRow row = sheet.GetRow(i + 1);//这样就是插入了
// 为第一列设置文本 这里的列也是从0开始的
row.CreateCell(j).SetCellValue("空");
}
}
//碰到a改成这样 碰到aa也是不变的
else if (sheetCellValue.ToString() == "a")
{
sheetCellValue.SetCellValue("原本为a" );
}
else
{
//如果某个内容为空 还用了下面这句话 那么就会报错:
//未将对象引用设置到对象的实例
// 5. 向单元格传值,以覆盖对应的单元格数据
sheetCellValue.SetCellValue(sheetCellValue + "更新");
}
}
}
// 6. 对 Workbook 的修改写入文件流,对文件进行相应操作
// 6. 对 Workbook 的修改写入文件流,对文件进行相应操作
FileStream file = new FileStream("C:\\log\\new.xlsx", FileMode.CreateNew, FileAccess.Write);//这是要保存的地址
ReadWorkbook.Write(file);
ReadWorkbook.Write(fsWrite);
file.Close();
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 7. 关闭文件流:报不报错都关闭
fsWrite.Close();
}
}
插入一行
private void button4_Click(object sender, EventArgs e)
{
// 创建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
try
{
// 1. 通过Sheet名 获取对应的ISeet--其中 ReadWorkbook 为读取Excel文档时获取
var sheet = ReadWorkbook.GetSheet("光照度");
// 2. 获取行数
int rowCount = sheet.LastRowNum;
//MessageBox.Show(rowCount.ToString());
// 3、获取列数 列数也是从0开始的
int columnount =3;
//创建第一行
{
IRow Row0 = sheet.CreateRow(rowCount+1);
for (int j = 0; j < columnount; j++)
{
ICell cell = Row0.CreateCell(j);
cell.SetCellValue("111");
}
}
// 6. 对 Workbook 的修改写入文件流,对文件进行相应操作
ReadWorkbook.Write(fsWrite);
}
catch (Exception ex)
{
throw ex;
}
finally
{
// 7. 关闭文件流:报不报错都关闭
fsWrite.Close();
}
}
}
插入图片
//插入图片 注意要用xlsx格式
private void button5_Click(object sender, EventArgs e)
{
// 创建文件流
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
// 第一步:读入图片数据
byte[] bytes = System.IO.File.ReadAllBytes(@"E:\StudyData_ele\testnew\NPOI\12.png");
//图片大小(不是图片占用字节)
//MessageBox.Show("bytes.Length:" + bytes.Length.ToString());
// 2.向Excel添加图片,获取到图片索引
int picIdx = ReadWorkbook.AddPicture(bytes, PictureType.PNG);
// 3.构建Excel图像
sheet1 = ReadWorkbook.GetSheet("Sheet1");
// 获取第二行,第一行是标题
//IRow row = sheet1.CreateRow(1);//这个是新创建一行 原本第二行都没有了
IRow row = sheet1.GetRow(1);//这样就是插入了
// 为第一列设置文本 这里的列也是从0开始的
row.CreateCell(1).SetCellValue("测试图片");
// 设置行高和列宽
//sheet1.SetColumnWidth(1, 413 * 32); // Excel的宽将1个像素分为32份
//row.Height = (short)(891 * 16); // Excel的高将1个像素分为16份
var drawing = sheet1.CreateDrawingPatriarch();
// 4.确定图像的位置
// new XSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, int col1, int row1, int col2, int row2)
// 前四个参数是单元格内的偏移量,这里需要填满整个单元格所以不设置。
// col1,row1表示图片的左上角在哪个单元格的左上角;col2,row2表示图片的右下角在哪个单元格的左上角
XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, 1, 1, 4, 4);
// 5.将图片设置到上面的位置中
drawing.CreatePicture(anchor, picIdx);
// 6. 对 Workbook 的修改写入文件流,对文件进行相应操作
ReadWorkbook.Write(fsWrite);
// 7. 关闭文件流:报不报错都关闭
fsWrite.Close();
}
另存为
// 创建文件流 这个是打开的源文件
FileStream fsWrite = new FileStream(FilePath, FileMode.Open, FileAccess.Write);
/*
.................
*/
// 6. 对 Workbook 的修改写入文件流,对文件进行相应操作
FileStream file = new FileStream("C:\\log\\new.xlsx", FileMode.CreateNew, FileAccess.Write);//这是要保存的地址
ReadWorkbook.Write(file);
// 7. 关闭文件流:报不报错都关闭
file.Close();
fsWrite.Close();
报错
Wrong Local header signature: 0xE011CFD0
文件应该是直接创建为后缀xlsx,而不是创建完成后改为这个。这样就会报错了