C#使用Npoi實(shí)現(xiàn)生成Word文檔
需求
按數(shù)據(jù)層級(jí)生成WORD文件,要有目錄,目錄里要有真實(shí)的頁(yè)碼,附件內(nèi)容用表格顯示,大標(biāo)題 做為封面當(dāng)獨(dú)顯示一頁(yè),
PDF內(nèi)容
大標(biāo)題,
目錄(里有對(duì)應(yīng)的頁(yè)碼)
正文 里有 表格
重點(diǎn):NPOI 在生成word文件時(shí)不會(huì)自動(dòng)生成總頁(yè)數(shù),所以本人使用了一個(gè)固定行索引來(lái)計(jì)算頁(yè)碼的功能。 使用 12 號(hào)字體,一頁(yè)是44行,按這個(gè)方法計(jì)算頁(yè)碼。有更好的方法可以在評(píng)論區(qū)告訴我。
表格使用方法也要注意
1.注意 CreateTable()方法里會(huì)默認(rèn)添加一行,這時(shí)如果使用 table.CreateRow() 方法創(chuàng)建新行這時(shí)就會(huì)有兩行。第一行為只有一個(gè)默認(rèn)的單元格。所有正確的方法是使用table.GetRow(0)方法
2.注意 table.CreateRow()方法也會(huì)默認(rèn)添一列,由于第一行已確定了表格的列數(shù)所要直接使用GetCell(0)方法獲取列對(duì)象,0表示列索引 AddNewTableCell()方法會(huì)在第一行的列數(shù)上再加列,所以正確的用法是GetCell(0)方法
代碼
/// <summary>
/// 生成報(bào)告詳情文件 pdf
/// </summary>
/// <param name="model"></param>
/// <param name="caseDetailsViewModels"></param>
/// <param name="TargetPath">目錄路徑</param>
/// <param name="NewFileName">文件名</param>
/// <returns></returns>
private static string generateWordFile(ViewModel model, List<detailsViewModel> detailsViewModels, string TargetPath, string NewFileName)
{
string outMergeFile = TargetPath + NewFileName;
int rowIndex = 0;//行索引
//TODO:使用FileStream文件流來(lái)寫(xiě)入數(shù)據(jù)(傳入?yún)?shù)為:文件所在路徑,對(duì)文件的操作方式,對(duì)文件內(nèi)數(shù)據(jù)的操作)
//通過(guò)使用文件流,創(chuàng)建文件流對(duì)象,向文件流中寫(xiě)入內(nèi)容,并保存為Word文檔格式
using (var stream = new FileStream(outMergeFile, FileMode.Create, FileAccess.Write))
{
//創(chuàng)建document文檔對(duì)象對(duì)象實(shí)例
XWPFDocument document = new XWPFDocument();
/**
*這里我通過(guò)設(shè)置公共的Word文檔中SetParagraph(段落)實(shí)例創(chuàng)建和段落樣式格式設(shè)置,大大減少了代碼的冗余,
* 避免每使用一個(gè)段落而去創(chuàng)建一次段落實(shí)例和設(shè)置段落的基本樣式
*(如下,ParagraphInstanceSetting為段落實(shí)例創(chuàng)建和樣式設(shè)置,后面索引表示為當(dāng)前是第幾行段落,索引從0開(kāi)始)
*/
//12號(hào)字 44行一頁(yè)
//for (int i = 1; i <= 50; i++)
//{
// document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, i.ToString(), true, 12, "黑體", ParagraphAlignment.CENTER), rowIndex);
// rowIndex++;
//}
int iPageNum = 1;//頁(yè)索引
int pageRowCount = 44;//每頁(yè)44行
//第一頁(yè)
for (int i = 1; i <= 21; i++)
{
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, String.Empty, true, 12, "黑體", ParagraphAlignment.CENTER), rowIndex);
rowIndex++;
}
//文本標(biāo)題 要顯示一頁(yè)
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, model.TitleModel.F_ContentStr ?? string.Empty, true, 20, "黑體", ParagraphAlignment.CENTER), rowIndex);
rowIndex++;
for (int i = 1; i <= 22; i++)
{
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, String.Empty, true, 12, "黑體", ParagraphAlignment.CENTER), rowIndex);
rowIndex++;
}
//空行
//document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Empty, true, 12, "宋體", ParagraphAlignment.LEFT), rowIndex);
//rowIndex++;
document.GetProperties().ExtendedProperties.GetUnderlyingProperties().Pages = iPageNum;
var fontSizeTwoTitle = 16;
var fontSizeTwoBody = 12;
var fontSize = 12;
iPageNum++;
//目錄最大行索引
var catalogueRowCount = iPageNum * pageRowCount;
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, "目錄", true, 16, "黑體", ParagraphAlignment.CENTER), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
//一、檢索目的...............................................4~4
var catalogueTest = "一、檢索目的...............................................4~4";
//目錄 要顯示一頁(yè)
//TODO:這里一行需要顯示兩個(gè)文本
foreach (var item in model.TwoTitleList)
{
if (!string.IsNullOrEmpty(item.F_ContentStr))
{
StringBuilder catalogueText = new StringBuilder(item.F_ContentStr);//string.Format(" {0}.{1}", item.F_ContentStr ?? string.Empty, item.F_Page ?? "1~1");
string pageNameTxt = !string.IsNullOrEmpty(item.F_Page) ? item.F_Page : "1~1";
int beginI = catalogueText.ToString().Length + pageNameTxt.Length;
for (int i = beginI; i < catalogueTest.Length; i++)
{
catalogueText.Append(".");
}
catalogueText.Append(pageNameTxt);
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, catalogueText.ToString(), false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
}
}
for (int i = rowIndex; i < catalogueRowCount; i++)
{
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, String.Empty, true, 12, "黑體", ParagraphAlignment.CENTER), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
}
#region 正文 從第三頁(yè)開(kāi)始
iPageNum = 3;
int beginPageNum = 3;
foreach (var item in model.TwoTitleList)
{
beginPageNum = document.GetProperties().ExtendedProperties.GetUnderlyingProperties().Pages;
//標(biāo)題
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format("{0}", item.F_ContentStr ?? string.Empty), false, fontSizeTwoTitle, "宋體", ParagraphAlignment.LEFT, false, String.Empty, "165DFF"), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
foreach (var itemThree in item.ThreeContentList)
{
itemThree.F_ContentStr = itemThree.F_ContentStr.Replace("\r\n", string.Empty);
//內(nèi)容
if (itemThree.F_ContentStr.Contains("</p>"))
{
var contentStr = itemThree.F_ContentStr.Replace("<p>", string.Empty);
var contentList = contentStr.Split("</p>");
foreach (var itemCon in contentList)
{
var itemConTxt = itemCon.Replace("\n", string.Empty).Trim();
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", itemConTxt), false, fontSizeTwoBody, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
}
}
else
{
var F_ContentStrTxt = itemThree.F_ContentStr.Replace("\n", string.Empty).Trim();
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", F_ContentStrTxt), false, fontSizeTwoBody, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
}
}
int pages = document.GetProperties().ExtendedProperties.GetUnderlyingProperties().Pages;
item.F_Page = string.Format("{0}~{1}", beginPageNum, pages);
iPageNum = pages;
}
#endregion
#region 附件
if (model.FileList != null && model.FileList.Count > 0)
{
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, " (一)檢索結(jié)果分析列表", false, fontSizeTwoTitle, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, " ", false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
int groupNum = 1;
foreach (var item in model.FileList)
{
var KeywordTxt = !string.IsNullOrEmpty(item.Keyword) ? item.Keyword : string.Empty;
KeywordTxt = KeywordTxt.Replace("\n", string.Empty).Trim();
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", KeywordTxt), false, fontSizeTwoBody, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, " ", false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
//注意CreateTable()方法里會(huì)默認(rèn)添加一行,這時(shí)如果使用 table.CreateRow() 方法創(chuàng)建新行這時(shí)就會(huì)有兩行。第一行為只有一個(gè)默認(rèn)的單元格
//所有正確的方法是使用table.GetRow(0);方法
var table = document.CreateTable();
XWPFTableRow tableHeadRow = table.GetRow(0);//新增行
tableHeadRow.GetCell(0).SetText("標(biāo)題");
tableHeadRow.GetCell(0).SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
var tableHeadRowCell_CaseCode = tableHeadRow.AddNewTableCell();
tableHeadRowCell_CaseCode.SetText("案號(hào)");
tableHeadRowCell_CaseCode.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
var tableHeadRowCell_IsAdd = tableHeadRow.AddNewTableCell();
tableHeadRowCell_IsAdd.SetText("是否加入檢索報(bào)告");
tableHeadRowCell_IsAdd.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
var tableHeadRowCell_NoAddCause = tableHeadRow.AddNewTableCell();
tableHeadRowCell_NoAddCause.SetText("未加入檢索報(bào)告原因");
tableHeadRowCell_NoAddCause.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
foreach (var itemKey in item.KeywordFileList)
{
//注意 table.CreateRow()方法也會(huì)默認(rèn)添一列,由于第一行已確定了表格的列數(shù)所要直接使用GetCell(0)方法獲取列對(duì)象,0表示列索引
//AddNewTableCell()方法會(huì)在第一行的列數(shù)上再加列,所以正確的用法是GetCell(0)方法
XWPFTableRow tableBodyRow = table.CreateRow();//新增行
//var tableBodyRowCell_Title = tableBodyRow.AddNewTableCell();
//tableBodyRowCell_Title.SetText(itemKey.F_CaseTitle ?? String.Empty);
//tableBodyRowCell_Title.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
tableBodyRow.GetCell(0).SetText(itemKey.F_CaseTitle ?? string.Empty);
//var tableBodyRowCell_CaseCode = tableBodyRow.AddNewTableCell();
//tableBodyRowCell_CaseCode.SetText(itemKey.F_CaseCode ?? String.Empty);
//tableBodyRowCell_CaseCode.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
tableBodyRow.GetCell(1).SetText(itemKey.F_CaseCode ?? string.Empty);
//var tableBodyRowCell_IsAdd = tableBodyRow.AddNewTableCell();
//tableBodyRowCell_IsAdd.SetText(itemKey.F_IsAdd ? "是" : "否");
//tableBodyRowCell_IsAdd.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
tableBodyRow.GetCell(2).SetText(itemKey.F_IsAdd ? "是" : "否");
tableBodyRow.GetCell(2).SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
//var tableBodyRowCell_NoAddCause = tableBodyRow.AddNewTableCell();
//tableBodyRowCell_NoAddCause.SetText(itemKey.F_NoAddCause ?? String.Empty);
//tableBodyRowCell_NoAddCause.SetVerticalAlignment(XWPFTableCell.XWPFVertAlign.CENTER);
tableBodyRow.GetCell(3).SetText(itemKey.F_NoAddCause ?? string.Empty);
groupNum++;
}
}
}
#endregion
#region 生成案例
if (caseDetailsViewModels != null && caseDetailsViewModels.Count > 0)
{
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" (二)檢索案例全文"), false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, " ", false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
foreach (var item in caseDetailsViewModels)
{
foreach (var itemCase in item.CaseItemList)
{
//標(biāo)題
var F_TitleTxt = itemCase.F_Title.Replace("\r\n", string.Empty);
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", F_TitleTxt), false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
//內(nèi)容
itemCase.F_Content = itemCase.F_Content.Replace("\r\n", string.Empty);
if (itemCase.F_Content.Contains("</p>"))
{
var contentStr = itemCase.F_Content.Replace("<p>", string.Empty);
var contentList = contentStr.Split("</p>");
foreach (var itemCon in contentList)
{
var itemConTxt = itemCon.Replace("\n", string.Empty).Trim();
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", itemConTxt), false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
//if (writer.PageNumber > iPageNum)
//{
// writePageNumber(document, writer, BF_Light);
//}
}
}
else
{
var F_ContentTxt = itemCase.F_Content.Replace("\n", string.Empty).Trim();
document.SetParagraph(NpoiWordParagraphTextStyleHelper._.ParagraphInstanceSetting(document, string.Format(" {0}", F_ContentTxt), false, fontSize, "宋體", ParagraphAlignment.LEFT), rowIndex);
setWordPages(document, ref rowIndex, pageRowCount, ref iPageNum);
}
}
}
}
#endregion
//向文檔流中寫(xiě)入內(nèi)容,生成word
document.Write(stream);
}
return outMergeFile;
}
/// <summary>
/// 設(shè)置word的Pages 總頁(yè)數(shù)
/// </summary>
/// <param name="document"></param>
/// <param name="rowIndex">行索引</param>
/// <param name="pageRowCount">每頁(yè)的總行數(shù)</param>
/// <param name="iPageNum">當(dāng)前頁(yè)索引</param>
private static void setWordPages(XWPFDocument document, ref int rowIndex, int pageRowCount, ref int iPageNum)
{
rowIndex++;
if (document != null)
{
if ((rowIndex % pageRowCount) == 0)
{
iPageNum++;
document.GetProperties().ExtendedProperties.GetUnderlyingProperties().Pages = iPageNum;
}
}
}調(diào)用
注意 要調(diào)用兩次,第一次生成時(shí)不知道目錄里的內(nèi)容在第幾頁(yè),第一次在生成時(shí)收集頁(yè)碼。這時(shí)會(huì)生成一個(gè)臨時(shí)文件。第二次生成的目錄里的頁(yè)碼才是真實(shí)有效的數(shù)據(jù)。所以要生成兩次。
就好比你在寫(xiě)WORD時(shí)也是不知道目錄里的內(nèi)容會(huì)寫(xiě)在第幾次,都是一、二級(jí)標(biāo)題和內(nèi)容都寫(xiě)完后,再去生成目錄的。這里的道理也是一樣的。
//word
var fileNameTempPath = generateWordFile(model, caseDetailsViewModels, uploadPath, fileNameTemp);
savePath = generateWordFile(model, caseDetailsViewModels, uploadPath, fileName);
//刪除臨時(shí)文件
if (File.Exists(fileNameTempPath))
{
File.Delete(fileNameTempPath);
}到此這篇關(guān)于C#使用Npoi實(shí)現(xiàn)生成Word文檔的文章就介紹到這了,更多相關(guān)C# Npoi生成Word內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
結(jié)合.net框架在C#派生類(lèi)中觸發(fā)基類(lèi)事件及實(shí)現(xiàn)接口事件
這篇文章主要介紹了結(jié)合.net框架在C#派生類(lèi)中觸發(fā)基類(lèi)事件及實(shí)現(xiàn)接口事件,示例的事件編程中包括接口和類(lèi)的繼承等面向?qū)ο蟮幕A(chǔ)知識(shí),需要的朋友可以參考下2016-02-02
C#簡(jiǎn)單訪問(wèn)SQLite數(shù)據(jù)庫(kù)的方法(安裝,連接,查詢(xún)等)
這篇文章主要介紹了C#簡(jiǎn)單訪問(wèn)SQLite數(shù)據(jù)庫(kù)的方法,涉及SQLite數(shù)據(jù)庫(kù)的下載、安裝及使用C#連接、查詢(xún)SQLIte數(shù)據(jù)庫(kù)的相關(guān)技巧,需要的朋友可以參考下2016-07-07
Unity3D開(kāi)發(fā)實(shí)戰(zhàn)之五子棋游戲
這篇文章主要為大家詳細(xì)介紹了Unity3D開(kāi)發(fā)實(shí)戰(zhàn)之五子棋游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09
Unity實(shí)現(xiàn)識(shí)別圖像中主體及其位置
EasyDL基于飛槳開(kāi)源深度學(xué)習(xí)平臺(tái),面向企業(yè)AI應(yīng)用開(kāi)發(fā)者提供零門(mén)檻AI開(kāi)發(fā)平臺(tái),實(shí)現(xiàn)零算法基礎(chǔ)定制高精度AI模型。本文將利用Unity和EasyDL實(shí)現(xiàn)識(shí)別圖像中主體及其位置,感興趣的可以了解一下2022-02-02
.NET中保證線程安全的高級(jí)方法Interlocked類(lèi)使用介紹
這篇文章主要介紹了.NET中保證線程安全的高級(jí)方法Interlocked類(lèi)使用介紹,Interlocked類(lèi)可以為為多個(gè)線程共享的變量提供原子操作,需要的朋友可以參考下2014-07-07
WPF利用WindowChrome實(shí)現(xiàn)自定義窗口
這篇文章主要為大家詳細(xì)介紹了WPF如何利用WindowChrome實(shí)現(xiàn)自定義窗口,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,需要的可以參考一下2023-02-02
C# 向二進(jìn)制文件進(jìn)行讀寫(xiě)的操作方法
該例子使用 BinaryStream 和 BinaryWriter 對(duì)二進(jìn)制文件進(jìn)行讀寫(xiě)操作先上代碼再根據(jù)我理解的所分享給各位朋友2013-04-04
C#使用oledb讀取excel表格內(nèi)容到datatable的方法
這篇文章主要介紹了C#使用oledb讀取excel表格內(nèi)容到datatable的方法,涉及C#操作oledb及datatable的相關(guān)技巧,需要的朋友可以參考下2015-05-05
c# 動(dòng)態(tài)加載dll文件,并實(shí)現(xiàn)調(diào)用其中的方法(推薦)
下面小編就為大家?guī)?lái)一篇c# 動(dòng)態(tài)加載dll文件,并實(shí)現(xiàn)調(diào)用其中的方法(推薦)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-02-02
C#強(qiáng)制轉(zhuǎn)換和嘗試轉(zhuǎn)換的方法
這篇文章主要為大家詳細(xì)介紹了C#強(qiáng)制轉(zhuǎn)換和嘗試轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09

