我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C# 基于NPOI操作Excel

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C# 基于NPOI操作Excel

1 单元格下拉框

在开发中我们会遇到为单元格设置下拉框。一般可以编写如下:


var cellRanges = new CellRangeAddressList(firstRow, lastRow, firstCol, latsCol);
DVConstraint constraint = DVConstraint.CreateExplicitListConstraint(stringArray);
HSSFDataValidation validate = new HSSFDataValidation(cellRanges, constraint);
validate.ShowProptBox = true;
sheet.AddValidationData(validate);

但是,如果字符串数组存在长度限制,如NPOI导出Excel时下拉列表值超过255的问题(String literals in formulas can't be bigger than 255 characters ASCII)
解决方案
通过额外新建Excel的Sheet页保存下拉内容,并转换为下拉框数据。


ISheet hidden = workbook.CreateSheet(columnName);
IRow row = null;
ICell cell = null;
for (int i = 0; i < stringArray.Length; i++)
{
    row = hidden.CreateRow(i);
    cell = row.CreateCell(0);
    cell.SetCellValue(stringArray[i]);
}
IName namedCell = workbook.CreateName();
namedCell.NameName = column.ColumnName;
// 注意下面的语法是Excel的公式,建议不要落掉一个`$`,很多文档都要所遗漏。
namedCell.RefersToFormula = $"{columnName}!$A$1:$A${stringArray.Length}";
DVConstraint constraint =  DVConstraint.CreateFormulaListConstraint(columnName);
CellRangeAddressList addressList = new CellRangeAddressList(firstRow, lastRow, firstCol, latsCol);
HSSFDataValidation validate = new HSSFDataValidation(addressList, constraint);
sheet.AddValidationData(dataValidate);

2 添加批注

代码如下:


HSSFPatriarch patriarch = (HSSFPatriarch)sheet.CreateDrawingPatriarch();
// 这个代码参数不要写成固定的,它用来定位你的批注的位置和大小。
HSSFComment comment = 
    (HSSFComment)patriarch.CreateCellComment(new HSSFFClientAnchor(0, 0, 255,255, col1, 0, col1 + 2, 5));
comment.Author = "Dison";
comment.String = new HSSFRichTextString($"内容");
cell.CellComment = comment;

3 读取数据

如何解析公式的结果
代码如下:


if (row.GetCell(i).CellType.Equals(CellType.Formula))
{
    var data = row.GetCell(i).RichStringCellValue;
}

如果希望读取公式也可以如下:


var data = row.GetCell(i).ToString();

但是需要注意结果没有等号“=”, 这里我是演示,所以写了局部变量。

日期格式 MM-dd-yy 转 yyyy-MM-dd
由于Excel的数字和日期都是Numeric格式,;处理如下:


if (row.GetCell(i).CellType.Equals(CellType.Numeric))
{
    ICell cell = row.GetCell(i);
    short format = cell.CellStyle.DataFormat;
    if (format != 0)
    {
        var data = cell.DateCellValue.ToString("yyyy-MM-dd");
    }
    else 
    {
        var data = cell.NumericCellValue;
    }
}

结语

NPOI还是一个相对成熟的Excel操作库。网上的资料确实写的比较潦草。但是作为程序员,必须学会耐心,尤其是debug。

常见问题解决

NPOI 导出添加批注功能


//添加批注
HSSFPatriarch patr = (HSSFPatriarch)sheet.CreateDrawingPatriarch();
HSSFComment comment12 = patr.CreateComment(new HSSFClientAnchor(0, 0, 0, 0, 1, 2, 2, 3));//批注显示定位
comment12.String = new HSSFRichTextString("请填写完整部门名称!");
HSSFCell cell12 = (HSSFCell)headerRow.CreateCell(12);//将批注给予单元格
cell12.CellComment = comment12;

但是有个比较重要的地方需要澄清下,就是批注的位置和大小,这是由HSSFClientAnchor八个参数控制的,千万不能简单的写HSSFClientAnchor(0, 0, 0, 0, 1, 2, 2, 3),

因为每个单元格的批注的位置都是不一样的(编辑批注时的位置)。那么怎么办呢,当然是需要了解参数的意思:

简单说来:

关于HSSFClientAnchor(dx1,dy1,dx2,dy2,col1,row1,col2,row2)的参数,有必要在这里说明一下:

  • dx1:起始单元格的x偏移量;
  • dy1:起始单元格的y偏移量;
  • dx2:终止单元格的x偏移量;
  • dy2:终止单元格的y偏移量;
  • col1:起始单元格列序号;
  • row1:起始单元格行序号;
  • col2:终止单元格列序号;
  • row2:终止单元格行序号;

其实主要是前四个是偏移量,后四个关系到批注的位置和大小。

以我自己做的一个例子来说:


HSSFComment comment1 = (HSSFComment)patr.CreateCellComment(new HSSFClientAnchor(255, 125, 1023, 150, colindex + 1, rowIndex - 1,  colindex + 2, rowIndex + 4));
  • rowIndex 是当前单元格是第几行,colindex 是当前单元格是第几列。通过行列是可以定位到当前的单元格的。
  • colindex + 1 对应上面的参数是col1  表示批注起始的位置是当前单元格的列数的下一列,即原来是第5列,则批注起在第6列。
  • rowIndex - 1 对应上面的参数是row1  表示皮质起始的位置是当前单元格行数的上一行,即原来是第2行,则批注起在第1行。
  • colindex + 2, rowIndex + 4  这两个参数则是单元格终止的位置   +2  +4  则是决定了批注的大小,道理同colindex + 1,rowIndex - 1 。

但是NPOI导出有个坑   就是批注大小会随着所在位置的单元格大小变动  这个影响不大  如果想解决这个问题   只能换导出方法了。。。

千万别按照网上人家写的(0, 0, 0, 0, 1, 2, 2, 3),这会坑死的,批注位置一直不变  任何单元格的批注都在同一个位置,坑死。

POI导出Excel时下拉列表值超过255的问题


//创建Excel工作薄对象

Workbook workbook = new HSSFWorkbook();

//生成一个表格 设置:页签

Sheet sheet = workbook.createSheet("sheet1");

 

//去数据库中查询我们想要的数据

List<Product> productList = Ebean.getServer(GlobalDBControl.getDB()) .createQuery(Product.class, "find product where 1 = 1 and status = 0 and producttype is not null ") .findList();

//创建一个数组 用来存放 我们取出来的数据

String[] productNameArray = new String[productList.size()];

//遍历每个peoduct对象,来获取productName属性并添加到数组中

for (int i = 0; i < productList.size(); i++)

{ Product product = productList.get(i);

productNameArray[i] = product.getTitle(); }

//将下拉框数据放到新的sheet里,然后excle通过新的sheet数据加载下拉框数据

Sheet hidden = workbook.createSheet("hidden");

//创建单元格对象 Cell cell = null;

//遍历我们上面的数组,将数据取出来放到新sheet的单元格中

for (int i = 0, length = productNameArray.length; i < length; i++)

{ //取出数组中的每个元素

String name = productNameArray[i];

//根据i创建相应的行对象(说明我们将会把每个元素单独放一行)

Row row = hidden.createRow(i);

//创建每一行中的第一个单元格

cell = row.createCell(0);

//然后将数组中的元素赋值给这个单元格

cell.setCellValue(name); }

 

// 创建名称,可被其他单元格引用

Name namedCell = workbook.createName(); namedCell.setNameName("hidden");

// 设置名称引用的公式

namedCell.setRefersToFormula("hidden!$A$1:$A$" + productNameArray.length);

//加载数据,将名称为hidden的sheet中的数据转换为List形式

DVConstraint constraint = DVConstraint.createFormulaListConstraint("hidden");

// 设置第一列的3-65534行为下拉列表

// (3, 65534, 0, 0) ====> (起始行,结束行,起始列,结束列)

CellRangeAddressList regions = new CellRangeAddressList(3, 65534, 0, 0);

// 将设置下拉选的位置和数据的对应关系 绑定到一起

DataValidation dataValidation = new HSSFDataValidation(regions, constraint);

//将第二个sheet设置为隐藏 workbook.setSheetHidden(1, true);

//将数据赋给下拉列表 sheet.addValidationData(dataValidation);

//最后将文件导出就可以了,后面的代码就不写了,我只写一些这个问题相关的代码

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

   如果出现多列情况,可复用下面方法

private void ExcelTo255(Workbook workbook,String sheetName,int sheetNameIndex,String[] sheetData,int firstRow,int lastRow,int firstCol,int lastCol){
    //将下拉框数据放到新的sheet里,然后excle通过新的sheet数据加载下拉框数据
    Sheet hidden = workbook.createSheet(sheetName);

    //创建单元格对象
    Cell cell =null;
    //遍历我们上面的数组,将数据取出来放到新sheet的单元格中
    for (int i = 0, length = sheetData.length; i < length; i++){
        //取出数组中的每个元素
        String name = sheetData[i];
        //根据i创建相应的行对象(说明我们将会把每个元素单独放一行)
        Row row = hidden.createRow(i);
        //创建每一行中的第一个单元格
        cell = row.createCell(0);
        //然后将数组中的元素赋值给这个单元格
        cell.setCellValue(name);
    }
    // 创建名称,可被其他单元格引用
    Name namedCell = workbook.createName();
    namedCell.setNameName(sheetName);
    // 设置名称引用的公式
    namedCell.setRefersToFormula(sheetName+"!$A$1:$A$" + sheetData.length);
    //加载数据,将名称为hidden的sheet中的数据转换为List形式
    DVConstraint constraint = DVConstraint.createFormulaListConstraint(sheetName);

    // 设置第一列的3-65534行为下拉列表
    // (3, 65534, 2, 2) ====> (起始行,结束行,起始列,结束列)
    CellRangeAddressList regions = new CellRangeAddressList(firstRow, lastRow, firstCol, lastCol);
    // 将设置下拉选的位置和数据的对应关系 绑定到一起
    DataValidation dataValidation = new HSSFDataValidation(regions, constraint);

    //将第二个sheet设置为隐藏
    workbook.setSheetHidden(sheetNameIndex, true);
    //将数据赋给下拉列表
    workbook.getSheetAt(0).addValidationData(dataValidation);
}

日期格式导入混乱

原因

大概是NPOI导入时会大概判断一下Excel文档里面的单元格是什么格式的内容,

有Blank,Boolean,Numeric,String,Error,Formula 等几种,

但是就是没有日期的,日期的单元格会被判断成Numeric(数字)类型,

所以日期格式的单元格就按数字类型来取其中的值,

所以单元格被判断成数字的之后还要再判断一下是否为日期格式。


/// <summary>
        /// 获取单元格类型
        /// </summary>
        /// <param name="cell"></param>
        /// <returns></returns>
        private static object GetValueType(ICell cell)
        {
            if (cell == null)
                return null;
            switch (cell.CellType)
            {
                case CellType.Blank: //BLANK:  
                    return null;
                case CellType.Boolean: //BOOLEAN:  
                    return cell.BooleanCellValue;
                case CellType.Numeric: //NUMERIC:  
                    short format = cell.CellStyle.DataFormat;
                    if (format != 0) { return cell.DateCellValue; } else { return cell.NumericCellValue; }
                case CellType.String: //STRING:  
                    return cell.StringCellValue;
                case CellType.Error: //ERROR:  
                    return cell.ErrorCellValue;
                case CellType.Formula: //FORMULA:  
                default:
                    return "=" + cell.CellFormula;
            }
        }

注意

使用时Excel里的长数字类型,否则这类数据可能会被误判为日期类型

如:0000123,2017001等这类型的需要处理一下单元格格式->设置成"常规"类型

以上就是C# 基于NPOI操作Excel的详细内容,更多关于C# NPOI操作Excel的资料请关注编程网其它相关文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C# 基于NPOI操作Excel

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C#基于NPOI怎么操作Excel

这篇文章主要介绍“C#基于NPOI怎么操作Excel”,在日常操作中,相信很多人在C#基于NPOI怎么操作Excel问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#基于NPOI怎么操作Excel”的疑惑有所
2023-06-30

C#中怎么用NPOI操作Excel

这篇“C#中怎么用NPOI操作Excel”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C#中怎么用NPOI操作Excel”文
2023-06-29

C#操作NPOI实现Excel数据导入导出

这篇文章主要为大家详细介绍了C#如何操作NPOI实现Excel数据导入导出功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
2023-02-15

关于Python操作Excel的基本方法

这篇文章主要介绍了关于Python操作Excel的基本方法,Python是一种功能强大的编程语言,可以用于许多任务,包括处理Excel文件,需要的朋友可以参考下
2023-05-18

C#读取Excel的操作

这篇文章主要讲解了“C#读取Excel的操作”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#读取Excel的操作”吧!C# 操作Excel之读取Excel操作的由来:看到论坛里面不断有人提
2023-06-17

python3编程基础:操作excel(

目录前言安装模块例1:创建一个excel 文件,并写入不同类的内容例2:写入时间例3:创建sheet例4 :操作单元格例5 :操作行/列/指定区域例6:显示小数例7:获取所有的行对象例8:获取所有的列对象例9:单元格类型例10:公式例11:
2023-01-31

关于Python自动化操作Excel

这篇文章主要介绍了关于Python自动化操作Excel,Python是一种功能强大的编程语言,可以用于许多任务,包括处理Excel文件,需要的朋友可以参考下
2023-05-15

C#怎么写入Excel操作

这篇文章主要介绍“C#怎么写入Excel操作”,在日常操作中,相信很多人在C#怎么写入Excel操作问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#怎么写入Excel操作”的疑惑有所帮助!接下来,请跟着小编
2023-06-18

C#调用Excel的操作方法

本篇内容主要讲解“C#调用Excel的操作方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#调用Excel的操作方法”吧!C# 操作Excel之Excel操作方法调用1.插入图片和线调用Pi
2023-06-17

Python基于win32com客户端实现Excel操作的详细过程

这篇文章主要介绍了Python基于win32com客户端实现Excel操作的详细过程,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-18

C# 操作Excel动态创建方法

本篇内容介绍了“C# 操作Excel动态创建方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!C# 操作Excel之动态创建的方法是什么呢?
2023-06-17

Java WorkBook对Excel的基本操作方法

这篇文章主要介绍了Java WorkBook对Excel的基本操作方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-14

C#操作Excel的方法有哪些

这篇文章主要介绍“C#操作Excel的方法有哪些”,在日常操作中,相信很多人在C#操作Excel的方法有哪些问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#操作Excel的方法有哪些”的疑惑有所帮助!接下来
2023-06-18

C#操作excel的方法是什么

这篇文章主要介绍“C#操作excel的方法是什么”,在日常操作中,相信很多人在C#操作excel的方法是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#操作excel的方法是什么”的疑惑有所帮助!接下来
2023-06-22

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录