C#使用NPOI操作Office
什么是NPOI
NPOI,顾名思义,就是POI的.NET版本。那POI又是什么呢?POI是一套用Java写成的库,能够帮助开发者在没有安装微软Office的情况下读写Office 97-2003的文件,支持的文件格式包括xls, doc, ppt等。
NPOI采用的是Apache 2.0许可证(poi也是采用这个许可证),这意味着它可以被用于任何商业或非商业项目,你不用担心因为使用它而必须开放你自己的源代码,所以它对于很多从事业务系统开发的公司来说绝对是很不错的选择。
官方网站:http://npoi.codeplex.com/
VisualStudio2019引入NPOI
在Nuget中引入NPOI包
NPOI操作word
1、word写入
由于NPOI在生成一个word文档时,标识标题等级的字符串是不固定的,这个时候通过使用模板的形式,来使word样式相对固定,也就是使用模板的样式来生成一个word文档,下面看代码:
XWPFDocument doc;
/// <summary>
/// 根据模板设置word文档样式
/// </summary>
public void SetDocStyles()
{
using (var dotStream = new FileStream("Resources\\模板.dotx", FileMode.Open, FileAccess.Read))
{
dotStream.Position = 0;
XWPFDocument template = new XWPFDocument(dotStream);
doc = new XWPFDocument();
XWPFStyles newStyles = doc.CreateStyles();
newStyles.SetStyles(template.GetCTStyle());
}
}
/// <summary>
/// 创建一个段落(也可以是标题)
/// </summary>
/// <param name="content">文字内容</param>
/// <param name="styleId">样式id,代表是多级标题或者段落正文</param>
/// <param name="fontFamily">字体</param>
/// <param name="IsBold">是否加粗</param>
/// <param name="fontSize">文字大小</param>
/// <param name="color">文字颜色</param>
/// <param name="paragraphAlignment">水平位置</param>
public void Write(string content, int fontSize, string styleId, string fontFamily, bool IsBold = false, string color = "black", ParagraphAlignmentCustom paragraphAlignment = ParagraphAlignmentCustom.Left)
{
XWPFParagraph ptitle = doc.CreateParagraph();
if(paragraphAlignment == ParagraphAlignmentCustom.Left)
ptitle.Alignment = ParagraphAlignment.LEFT;
else if (paragraphAlignment == ParagraphAlignmentCustom.Center)
ptitle.Alignment = ParagraphAlignment.CENTER;
XWPFRun titlerun = ptitle.CreateRun();
titlerun.SetText(content);
titlerun.IsBold = IsBold;
titlerun.FontFamily = fontFamily;
titlerun.FontSize = fontSize;
titlerun.SetColor(color);
ptitle.Style = styleId;
ptitle.SetNumID("");
}
/// <summary>
/// 插入图片
/// </summary>
/// <param name="picPath"></param>
/// <param name="pictureName"></param>
public void InsertPicture(string picPath,string pictureName)
{
FileStream gfs = new FileStream(picPath, FileMode.Open, FileAccess.Read);
CT_P m_p = doc.Document.body.AddNewP();
m_p.AddNewPPr().AddNewJc().val = ST_Jc.center;//段落水平居中
XWPFParagraph gp = new XWPFParagraph(m_p, doc);//创建段落
XWPFRun gr = gp.CreateRun();//创建run
//在run中插入图片
gr.AddPicture(gfs, (int)PictureType.PNG, pictureName, 5300000, 2500000);
}
/// <summary>
/// 保存word文档
/// </summary>
/// <param name="filePath"></param>
public void SaveDoc(string filePath)
{
FileStream fs = new FileStream(filePath, FileMode.Create);
doc.Write(fs);
fs.Close();
doc.Close();
}
2、word读取
/// <summary>
/// 获取word文档所有段落
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
private List<XWPFParagraph> GetParagraphs(string filePath)
{
var dotStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
XWPFDocument doc = new XWPFDocument(dotStream);
foreach(var paragraph in doc.Paragraphs)
{
var styleId=paragraph.StyleID;//标题等级标识
}
return doc.Paragraphs;
}
NPOI操作Excel
这是一个大佬写的,用到的很全面,传送门:https://www.cnblogs.com/knowledgesea/archive/2012/11/16/2772547.html
//创建一个常用的xls文件
private void button3_Click(object sender, EventArgs e)
{
IWorkbook wb = new HSSFWorkbook();
//创建表
ISheet sh = wb.CreateSheet("zhiyuan");
//设置单元的宽度
sh.SetColumnWidth(0, 15 * 256);
sh.SetColumnWidth(1, 35 * 256);
sh.SetColumnWidth(2, 15 * 256);
sh.SetColumnWidth(3, 10 * 256);
int i = 0;
#region 练习合并单元格 sh.AddMergedRegion(new NPOI.SS.Util.CellRangeAddress(0, 0, 0, 3));
//CellRangeAddress()该方法的参数次序是:开始行号,结束行号,开始列号,结束列号。 IRow row0 = sh.CreateRow(0);
row0.Height = 20 * 20;
ICell icell1top0 = row0.CreateCell(0);
icell1top0.CellStyle = Getcellstyle(wb, stylexls.头);
icell1top0.SetCellValue("标题合并单元");
#endregion
i++;
#region 设置表头
IRow row1 = sh.CreateRow(1);
row1.Height = 20 * 20;
ICell icell1top = row1.CreateCell(0);
icell1top.CellStyle = Getcellstyle(wb, stylexls.头);
icell1top.SetCellValue("网站名");
ICell icell2top = row1.CreateCell(1);
icell2top.CellStyle = Getcellstyle(wb, stylexls.头);
icell2top.SetCellValue("网址");
ICell icell3top = row1.CreateCell(2);
icell3top.CellStyle = Getcellstyle(wb, stylexls.头);
icell3top.SetCellValue("百度快照");
ICell icell4top = row1.CreateCell(3);
icell4top.CellStyle = Getcellstyle(wb, stylexls.头);
icell4top.SetCellValue("百度收录");
#endregion
using(FileStream stm=File.OpenWrite(@"c:/myMergeCell.xls"))
{
wb.Write(stm);
MessageBox.Show("提示:创建成功!");
}
}
#region 定义单元格常用到样式的枚举
public enum stylexls
{
头,
url,
时间,
数字,
钱,
百分比,
中文大写,
科学计数法,
默认
}
#endregion
#region 定义单元格常用到样式
static ICellStyle Getcellstyle(IWorkbook wb, stylexls str)
{
ICellStyle cellStyle = wb.CreateCellStyle();
//定义几种字体
//也可以一种字体,写一些公共属性,然后在下面需要时加特殊的
IFont font12 = wb.CreateFont();
font12.FontHeightInPoints = 10;
font12.FontName = "微软雅黑";
IFont font = wb.CreateFont();
font.FontName = "微软雅黑";
//font.Underline = 1;下划线
IFont fontcolorblue = wb.CreateFont();
fontcolorblue.Color = HSSFColor.OLIVE_GREEN.BLUE.index;
fontcolorblue.IsItalic = true;//下划线
fontcolorblue.FontName = "微软雅黑";
//边框
cellStyle.BorderBottom = NPOI.SS.UserModel.BorderStyle.DOTTED;
cellStyle.BorderLeft = NPOI.SS.UserModel.BorderStyle.HAIR;
cellStyle.BorderRight = NPOI.SS.UserModel.BorderStyle.HAIR;
cellStyle.BorderTop = NPOI.SS.UserModel.BorderStyle.DOTTED;
//边框颜色
cellStyle.BottomBorderColor = HSSFColor.OLIVE_GREEN.BLUE.index;
cellStyle.TopBorderColor = HSSFColor.OLIVE_GREEN.BLUE.index;
//背景图形,我没有用到过。感觉很丑
//cellStyle.FillBackgroundColor = HSSFColor.OLIVE_GREEN.BLUE.index;
//cellStyle.FillForegroundColor = HSSFColor.OLIVE_GREEN.BLUE.index;
cellStyle.FillForegroundColor = HSSFColor.WHITE.index;
// cellStyle.FillPattern = FillPatternType.NO_FILL;
cellStyle.FillBackgroundColor = HSSFColor.BLUE.index;
//水平对齐
cellStyle.Alignment = NPOI.SS.UserModel.HorizontalAlignment.LEFT;
//垂直对齐
cellStyle.VerticalAlignment = VerticalAlignment.CENTER;
//自动换行
cellStyle.WrapText = true;
//缩进;当设置为1时,前面留的空白太大了。希旺官网改进。或者是我设置的不对
cellStyle.Indention = 0;
//上面基本都是设共公的设置
//下面列出了常用的字段类型
switch (str)
{
case stylexls.头:
// cellStyle.FillPattern = FillPatternType.LEAST_DOTS;
cellStyle.SetFont(font12);
break;
case stylexls.时间:
IDataFormat datastyle = wb.CreateDataFormat();
cellStyle.DataFormat = datastyle.GetFormat("yyyy/mm/dd");
cellStyle.SetFont(font);
break;
case stylexls.数字:
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00");
cellStyle.SetFont(font);
break;
case stylexls.钱:
IDataFormat format = wb.CreateDataFormat();
cellStyle.DataFormat = format.GetFormat("¥#,##0");
cellStyle.SetFont(font);
break;
case stylexls.url:
fontcolorblue.Underline = 1;
cellStyle.SetFont(fontcolorblue);
break;
case stylexls.百分比:
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00%");
cellStyle.SetFont(font);
break;
case stylexls.中文大写:
IDataFormat format1 = wb.CreateDataFormat();
cellStyle.DataFormat = format1.GetFormat("[DbNum2][$-804]0");
cellStyle.SetFont(font);
break;
case stylexls.科学计数法:
cellStyle.DataFormat = HSSFDataFormat.GetBuiltinFormat("0.00E+00");
cellStyle.SetFont(font);
break;
case stylexls.默认:
cellStyle.SetFont(font);
break;
}
return cellStyle;
}
#endregion
使用NPOI遇到的坑
1、NPOI操作word的时候,在上面方法中Write的参数“styleId”是一个坑,因为styleid根据不同文档值不同,比如在A文档中的标题1对应的styleId为“a5”,但是在B文档中的标题1对应的可能是“17”。所以我使用了一个word模板,可以通过调试拿到模板中各个段落的styleId,在生成word时会用到。
2、在操作word时,write方法中开始没有写最后一句“ptitle.SetNumID("");”,在生成word文档之后,wps打开正常,用msword打开后则自动产生了标题编号,但是调试的时候ptitle.NumLevelText的值却是null,最后尝试ptitle.SetNumID(""),再次用msword打开,显示正常了。
如果有不对的地方,还请指出,共同进步!