zoukankan      html  css  js  c++  java
  • C#调用NPOI组件读取excel表格数据转为datatable写入word表格中并向word中插入图片/文字/书签 获得书签列表

    调用word的com组件将400条数据导入word表格中耗时10分钟简直不能忍受,使用NPOI组件耗时4秒钟.但是NPOI中替换书签内容的功能不知道是不支持还是没找到.

    辅助类 Excel表格数据与DataTable互转:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using NPOI.SS.UserModel;
    using NPOI.XSSF.UserModel;
    using NPOI.HSSF.UserModel;
    using System.IO;
    using System.Data;
    
    namespace Utils
    {
        //http://www.cnblogs.com/luxiaoxun/p/3374992.html
        public class ExcelDataTableConverter : IDisposable
        {
            private string fileName = null; //文件名
            private IWorkbook workbook = null;
            private FileStream fs = null;
            private bool disposed;
    
            public ExcelDataTableConverter(string fileName)
            {
                this.fileName = fileName;
                disposed = false;
            }
    
            /// <summary>
            /// 将DataTable数据导入到excel中
            /// </summary>
            /// <param name="data">要导入的数据</param>
            /// <param name="isColumnWritten">DataTable的列名是否要导入</param>
            /// <param name="sheetName">要导入的excel的sheet的名称</param>
            /// <returns>导入数据行数(包含列名那一行)</returns>
            public int DataTableToExcel(DataTable data, string sheetName, bool isColumnWritten)
            {
                int i = 0;
                int j = 0;
                int count = 0;
                ISheet sheet = null;
    
                fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                if (fileName.IndexOf(".xlsx") > 0) // 2007版本
                    workbook = new XSSFWorkbook();
                else if (fileName.IndexOf(".xls") > 0) // 2003版本
                    workbook = new HSSFWorkbook();
    
                try
                {
                    if (workbook != null)
                    {
                        sheet = workbook.CreateSheet(sheetName);
                    }
                    else
                    {
                        return -1;
                    }
    
                    if (isColumnWritten == true) //写入DataTable的列名
                    {
                        IRow row = sheet.CreateRow(0);
                        for (j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Columns[j].ColumnName);
                        }
                        count = 1;
                    }
                    else
                    {
                        count = 0;
                    }
    
                    for (i = 0; i < data.Rows.Count; ++i)
                    {
                        IRow row = sheet.CreateRow(count);
                        for (j = 0; j < data.Columns.Count; ++j)
                        {
                            row.CreateCell(j).SetCellValue(data.Rows[i][j].ToString());
                        }
                        ++count;
                    }
                    workbook.Write(fs); //写入到excel
                    return count;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    return -1;
                }
            }
    
            /// <summary>
            /// 将excel中的数据导入到DataTable中
            /// </summary>
            /// <param name="sheetName">excel工作薄sheet的名称</param>
            /// <param name="isFirstRowColumn">第一行是否是DataTable的列名</param>
            /// <returns>返回的DataTable</returns>
            public DataTable ExcelToDataTable(string sheetName, bool isFirstRowColumn)
            {
                ISheet sheet = null;
                DataTable data = new DataTable();
                int startRow = 0;
                try
                {
                    fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
                    if (fileName.IndexOf(".xlsx") > 0) // 2007版本
                        workbook = new XSSFWorkbook(fs);
                    else if (fileName.IndexOf(".xls") > 0) // 2003版本
                        workbook = new HSSFWorkbook(fs);
    
                    if (sheetName != null)
                    {
                        sheet = workbook.GetSheet(sheetName);
                        if (sheet == null) //如果没有找到指定的sheetName对应的sheet,则尝试获取第一个sheet
                        {
                            sheet = workbook.GetSheetAt(0);
                        }
                    }
                    else
                    {
                        sheet = workbook.GetSheetAt(0);
                    }
                    if (sheet != null)
                    {
                        IRow firstRow = sheet.GetRow(0);
                        int cellCount = firstRow.LastCellNum; //一行最后一个cell的编号 即总的列数
    
                        if (isFirstRowColumn)
                        {
                            for (int i = firstRow.FirstCellNum; i < cellCount; ++i)
                            {
                                ICell cell = firstRow.GetCell(i);
                                if (cell != null)
                                {
                                    string cellValue = cell.StringCellValue;
                                    if (cellValue != null)
                                    {
                                        DataColumn column = new DataColumn(cellValue);
                                        data.Columns.Add(column);
                                    }
                                }
                            }
                            startRow = sheet.FirstRowNum + 1;
                        }
                        else
                        {
                            startRow = sheet.FirstRowNum;
                        }
    
                        //最后一列的标号
                        int rowCount = sheet.LastRowNum;
                        for (int i = startRow; i <= rowCount; ++i)
                        {
                            IRow row = sheet.GetRow(i);
                            if (row == null) continue; //没有数据的行默认是null       
                            
                            DataRow dataRow = data.NewRow();
                            for (int j = row.FirstCellNum; j < cellCount; ++j)
                            {
                                if (row.GetCell(j) != null) //同理,没有数据的单元格都默认是null
                                {
                                    //dataRow[j] = row.GetCell(j).ToString();  //19890603会显示成MIDB(C2,7,6)
                                    dataRow[j] = row.GetCell(j).StringCellValue;
                                }
                            }
                            data.Rows.Add(dataRow);
                        }
                    }
    
                    return data;
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception: " + ex.Message);
                    return null;
                }
            }
    
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
    
            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        if (fs != null)
                            fs.Close();
                    }
    
                    fs = null;
                    disposed = true;
                }
            }
        }
    }

    调用:


    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using NPOI.XWPF.UserModel;
    using NPOI.OpenXmlFormats.Wordprocessing;
    using System.IO;
    
    namespace WordNPOI
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            XWPFDocument doc = new XWPFDocument();
    
            private void Form1_Load(object sender, EventArgs e)
            {
    
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                Utils.ExcelDataTableConverter edc = new Utils.ExcelDataTableConverter("60岁以上人员.xlsx");
                DataTable dt = edc.ExcelToDataTable("sheet1", true);
    
                int rowCount = dt.Rows.Count;
                int columnCount = dt.Columns.Count;
    
    
                //创建段落对象
                XWPFParagraph p1 = doc.CreateParagraph();
                //创建run对象
                //本节提到的所有样式都是基于XWPFRun的,
                //你可以把XWPFRun理解成一小段文字的描述对象,
                //这也是Word文档的特征,即文本描述性文档。
                //来自Tony Qu http://tonyqus.sinaapp.com/archives/609
                XWPFRun r1 = p1.CreateRun();
                r1.SetBold(true);
                r1.SetText("数据导出demo");
                r1.SetBold(true);
                r1.FontFamily = "宋体";
                r1.FontSize = 26;
                //r1.SetFontFamily("Arial");//设置雅黑字体
                //创建表格对象,行 列
                XWPFTable table = doc.CreateTable(rowCount + 1, columnCount);
    
    
                
    
                //添加列头
                for (int i = 0; i < columnCount; i++)
                {
                    var ctt = table.GetRow(0).GetCell(i).GetCTTc();
                    var tcPr = ctt.AddNewTcPr();
                    tcPr.tcW = new CT_TblWidth();
                    tcPr.tcW.w = "6000";//单元格宽 单位是EMU,1英寸= 914400 EMU http://bbs.csdn.net/topics/390906055
                    tcPr.tcW.type = ST_TblWidth.dxa;
                    //table.SetColumnWidth(i, 5500);  //无效果 特定数字5500又太大 貌似要设置为n*256
    
    
                    //设置单元格字体 样式 http://www.tuicool.com/articles/JFZzUj
                    var p = table.GetRow(0).GetCell(i).AddParagraph();
                    
                    XWPFRun r = p.CreateRun();
                    r.FontFamily = "宋体";
                    r.FontSize = 10;
                    r.SetBold(true);
                    r.SetText(dt.Columns[i].ColumnName);
                }
    
               
    
    
                for (int i = 1; i < rowCount; i++)
                {
                    for (int j = 0; j < columnCount; j++)
                    {
                        string tem = dt.Rows[i][j].ToString();
                        table.GetRow(i).GetCell(j).SetText(dt.Rows[i][j].ToString());
                    }
                }
    
    
                //插入图片
                var gfs = new FileStream("1.png", FileMode.Open, FileAccess.Read);
                var gp = doc.CreateParagraph();
                gp.Alignment = ParagraphAlignment.CENTER; //居中
                var gr = gp.CreateRun();
                gr.AddPicture(gfs, (int)PictureType.JPEG, "1.png", 1000000, 1000000); //1000000 差不多100像素多一点
                gfs.Close();
    
    
                var gp1 = doc.CreateParagraph();
                gp1.CreateRun().SetText("The End");
    
    
                //bookmark书签
    
                var items = doc.Paragraphs[0].Document.BodyElements;
    
                //CT_Bookmark b = new CT_Bookmark();
                
    
                //CT_Bookmark ctBookmark = doc.Paragraphs[0].GetBookmarkStartArray(0);
    
                //foreach (CT_Bookmark bookmark in doc.Paragraphs[0].GetCTP().GetBookmarkStartList()) //网上的代码,发现找不到这个方法
                //{
                //    Assert.AreEqual("poi", bookmark.name);
                //}
    
    
    
    
                //书签0开始
                int m_bookId = 0;//同一段内有多个书签,需要不同的Id,不同段的书签Id可以相同
    
                CT_P m_p = doc.Document.body.AddNewP();
    
                m_p.AddNewPPr().AddNewJc().val = ST_Jc.both;
    
                m_p.AddNewPPr().AddNewSpacing().line = "400";//固定行距20磅
    
                m_p.AddNewPPr().AddNewSpacing().lineRule = ST_LineSpacingRule.exact;
    
                m_p.Items = new System.Collections.ArrayList();
    
                CT_Bookmark m_ctbook1 = new CT_Bookmark();
    
                m_bookId = m_p.Items.Count;
    
                m_ctbook1.id = m_bookId.ToString(); //"0";
    
                m_ctbook1.name = "NPOI1";//书签名,超链接用
    
                m_p.Items.Add(m_ctbook1);
    
                m_p.ItemsElementName = new List<ParagraphItemsChoiceType>();
    
                m_p.ItemsElementName.Add(ParagraphItemsChoiceType.bookmarkStart);
    
                m_p.AddNewR().AddNewT().Value = "1、NPOI介绍";
    
                //书签0结束
    
                m_ctbook1 = new CT_Bookmark();
    
                m_ctbook1.id = m_bookId.ToString();//"0";
    
                m_p.Items.Add(m_ctbook1);
    
                m_p.ItemsElementName.Add(ParagraphItemsChoiceType.bookmarkEnd);
    
    
    
                //获得书签
                int pcount = doc.Document.body.ItemsElementName.Count();
                List<CT_Bookmark> bkList = new List<CT_Bookmark>();
                for (int i = 0; i < pcount; i++)
                {
                    var ctp = doc.Document.body.GetPArray(i);
                    if (ctp!=null)
                    {
                        var tempBookMarkList = ctp.GetBookmarkStartList();
                        bkList.AddRange(tempBookMarkList);
                    }
                }
    
                foreach (var bookMark in bkList)
                {//替换书签内容?????????????????找不到示例代码还是不支持此功能?
                    bookMark.colFirst = "1";
                    bookMark.colLast = "2";
                    bookMark.displacedByCustomXmlSpecified = true;
    
                    
    
                    MessageBox.Show(bookMark.name);
                    
                }
    
    
                //保存文件到磁盘
                FileStream out1 = new FileStream("simpleTable.docx", FileMode.OpenOrCreate);
                doc.Write(out1);
                out1.Close();
    
                MessageBox.Show("done");
            }
        }
    }
    

    关于宽高设置:

    http://www.oschina.net/code/snippet_222150_9780

     
    在Excel中,单元格的宽度其实就是列的宽度,因为Excel假设这一列的单元格的宽度肯定一致。所以要设置单元格的宽度,我们就得从列的宽度下手,HSSFSheet有个方法叫SetColumnWidth,共有两个参数:一个是列的索引(从0开始),一个是宽度。
    现在假设你要设置B列的宽度,就可以用下面的代码:
    HSSFWorkbook hssfworkbook = new HSSFWorkbook();
    HSSFSheet sheet1 = hssfworkbook.CreateSheet("Sheet1");
    sheet1.SetColumnWidth(1, 100 * 256);
    这里你会发现一个有趣的现象,SetColumnWidth的第二个参数要乘以256,这是怎么回事呢?其实,这个参数的单位是1/256个字符宽度,也就是说,这里是把B列的宽度设置为了100个字符。
    刚才说的是如何设置,那如何去读取一个列的宽度呢?直接用GetColumnWidth方法,这个方法只有一个参数,那就是列的索引号。如下所示:
    int col1width = sheet1.GetColumnWidth(1);
      
    说完宽度,我们来说高度,在Excel中,每一行的高度也是要求一致的,所以设置单元格的高度,其实就是设置行的高度,所以相关的属性也应该在HSSFRow上,它就是HSSFRow.Height和HeightInPoints,这两个属性的区别在于HeightInPoints的单位是点,而Height的单位是1/20个点,所以Height的值永远是HeightInPoints的20倍。
    要设置第一行的高度,可以用如下代码:
    sheet1.CreateRow(0).Height = 200*20;
    或者
    sheet1.CreateRow(0).HeightInPoints = 200;
    如果要获得某一行的行高,可以直接拿HSSFRow.Height属性的返回值。
      
    你可能觉得一行一行设置行高或者一列一列设置列宽很麻烦,那你可以考虑使用HSSFSheet.DefaultColumnWidth、HSSFSheet.DefaultRowHeight和HSSFSheet.DefaultRowHeightInPoints属性。
    一旦设置了这些属性,如果某一行或者某一列没有设置宽度,就会使用默认宽度或高度。代码如下:
    sheet1.DefaultColumnWidth=100*256;
    sheet1.DefaultRowHeight=30*20;

    版权声明:本文为博主原创文章,未经博主允许不得转载。

    作者:xuejianxiyang
    出处:http://xuejianxiyang.cnblogs.com
    关于作者:Heaven helps those who help themselves.
    本文版权归原作者和博客园共有,欢迎转载,但未经原作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    ab测试curl json语句
    Python进阶-----静态方法@property,@classmethod,@staticmethod【转】
    staticmethod写和不写有什么区别?【转】
    使用 febootstrap 制作自定义基础镜像【转】
    k8s
    Linux服务器扩容VG时报错 Couldn't create temporary archive name.
    2020年的一些思考和总结
    谈谈FTP
    NET::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)
    Centos7 cache/buff过高处理方法
  • 原文地址:https://www.cnblogs.com/xuejianxiyang/p/4862072.html
Copyright © 2011-2022 走看看