3.4用NPOI操作EXCEL--从Excel中抽取文本

  我们知道,搜索引擎最擅长处理的就是文本,而Excel中的内容并不是以文本方式存储的。那么如果想要搜索引擎爬虫能够抓取到Excel中的内容是比较困难的,除非搜索引擎爬虫对Excel格式进行专门的处理。那么有没有办法解决此问题呢?有,通过NPOI将Excel内容文本化!

  如下,有这样一张Excel,如果想让它被搜索引擎收录,常用的方式是以HTML形式展现,但将一个个这样的Excel手工做成HTML页面显然比较麻烦。接下来,我们将提供一种方案,自动将Excel中的内容以HTML形式展现。

  其实基本思想也很简单,就是通过NPOI读取每个Cell中的内容,然后以HTML的形式输出。但要保证输出的HTML页面布局与Excel中的一致,还有点小技巧。下面是构造Table的代码:

private HSSFSheet sht;
protected String excelContent;

protected void Page_Load(object sender, EventArgs e)
{
    HSSFWorkbook wb = new HSSFWorkbook(new FileStream(Server.MapPath("App_Data/quotation.xls"), FileMode.Open));
    sht = wb.GetSheet("Sheet1");

//取行Excel的最大行数
    int rowsCount = sht.PhysicalNumberOfRows;
    //为保证Table布局与Excel一样,这里应该取所有行中的最大列数(需要遍历整个Sheet)。
    //为少一交全Excel遍历,提高性能,我们可以人为把第0行的列数调整至所有行中的最大列数。
    int colsCount = sht.GetRow(0).PhysicalNumberOfCells;

int colSpan;
    int rowSpan;
    bool isByRowMerged;

StringBuilder table = new StringBuilder(rowsCount * 32);

table.Append("<table border='1px'>");
    for (int rowIndex = 0; rowIndex < rowsCount; rowIndex++)
    {
        table.Append("<tr>");
        for (int colIndex = 0; colIndex < colsCount; colIndex++)
        {
            GetTdMergedInfo(rowIndex, colIndex, out colSpan, out rowSpan, out isByRowMerged);
            //如果已经被行合并包含进去了就不输出TD了。
            //注意被合并的行或列不输出的处理方式不一样,见下面一处的注释说明了列合并后不输出TD的处理方式。
            if (isByRowMerged)
            {
                continue;
            }
            
            table.Append("<td");
            if (colSpan > 1)
                table.Append(string.Format(" colSpan={0}", colSpan));
            if (rowSpan > 1)
                table.Append(string.Format(" rowSpan={0}", rowSpan));
            table.Append(">");

table.Append(sht.GetRow(rowIndex).GetCell(colIndex));

//列被合并之后此行将少输出colSpan-1个TD。
            if (colSpan > 1)
                colIndex += colSpan - 1;

table.Append("</td>");

}
        table.Append("</tr>");
    }
    table.Append("</table>");

this.excelContent = table.ToString();
}

  其中用到的GetTdMergedInfo方法代码如下:

/// <summary>
///  获取Table某个TD合并的列数和行数等信息。与Excel中对应Cell的合并行数和列数一致。
/// </summary>
/// <param name="rowIndex">行号</param>
/// <param name="colIndex">列号</param>
/// <param name="colspan">TD中需要合并的行数</param>
/// <param name="rowspan">TD中需要合并的列数</param>
/// <param name="rowspan">此单元格是否被某个行合并包含在内。如果被包含在内,将不输出TD。</param>
/// <returns></returns>
private void GetTdMergedInfo(int rowIndex, int colIndex, out int colspan, out int rowspan, out bool isByRowMerged)
{
    colspan = 1;
    rowspan = 1;
    isByRowMerged = false;
    int regionsCuont = sht.NumMergedRegions;
    Region region;
    for (int i = 0; i < regionsCuont; i++)
    {
        region = sht.GetMergedRegionAt(i);
        if (region.RowFrom == rowIndex && region.ColumnFrom == colIndex)
        {
            colspan = region.ColumnTo - region.ColumnFrom + 1;
            rowspan = region.RowTo - region.RowFrom + 1;

return;
        }
        else if (rowIndex > region.RowFrom && rowIndex <= region.RowTo && colIndex>=region.ColumnFrom && colIndex<=region.ColumnTo)
        {
            isByRowMerged = true;
        }
    }
}

最后在apsx页面中输出构建好的Table:

<%=excelContent %>

执行效果如下:

我们发现,与Excel中的布局完全一样(这里没有处理单元格的样式,只处理了内容,有兴趣的读者也可以将Excel中单元格的样式也应用在HTML中)。这里为保证布局一致,主要是将Excel中的Region信息解析成Table的colSpan和rowSpan属性,如果对这两个属性不太了解,可以结合以下代码和示例加以了解:

<table width="300px" border="1px">
<tr>
    <td colspan="2" rowspan="2">0,0</td>
    <td>0,3</td>
</tr>
<tr>
    <td>1,3</td>
</tr>
<tr>
    <td rowspan="2">2,0</td>
    <td colspan="2">2,1</td>
</tr>
<tr>
    <td>3,1</td>
    <td>3,2</td>
</tr>
</table>

以上HTML代码对应的Table展现为

二,

首先我们要准备一个用于打开文件流的函数InitializeWorkbook,由于文件读完后就没用了,所以这里直接用using(养成好习惯,呵呵)。

HSSFWorkbookhssfworkbook;

void InitializeWorkbook(string path)
{
    //read the template via FileStream, it is suggested to use FileAccess.Readto prevent file lock.

//book1.xlsis an Excel-2007-generated file, so some new unknown BIFF records are added.

using (FileStream file =new FileStream(path, FileMode.Open,FileAccess.Read))
    {
        hssfworkbook = newHSSFWorkbook(file);
    }
}

接下来我们要开始写最重要的函数ConvertToDataTable,即把HSSF的数据放到一个DataTable中。

HSSFSheetsheet = hssfworkbook.GetSheetAt(0);
System.Collections.IEnumerator rows = sheet.GetRowEnumerator();

while(rows.MoveNext())
{
    HSSFRow row = (HSSFRow)rows.Current;
    //TODO::Create DataTable row

for (int i = 0; i < row.LastCellNum; i++)
    {
        HSSFCell cell = row.GetCell(i);
        //TODO::set cell value to the cell of DataTables

}

上面的结构大家都应该能看懂吧,无非就是先遍历行,再遍历行中的每一列。这里引出了一个难点,由于Excel的单元格有好几种类型,类型不同显示的东西就不同,具体的类型有布尔型、数值型、文本型、公式型、空白、错误。

publicenum HSSFCellType
{
    Unknown = -1,
    NUMERIC = 0,
    STRING = 1,
    FORMULA = 2,
    BLANK = 3,
    BOOLEAN = 4,
    ERROR = 5,
}

这里的HSSFCellType描述了所有的类型,但细心的朋友可能已经发现了,这里没有日期型,这是为什么呢?这是因为Excel底层并没有一定日期型,而是通过数值型来替代,至于如何区分日期和数字,都是由文本显示的样式决定的,在NPOI中则是由HSSFDataFormat来处理。为了能够方便的获得所需要的类型所对应的文本,我们可以使用HSSFCell.ToString()来处理。

于是刚才的代码则变成了这样:

HSSFSheetsheet = hssfworkbook.GetSheetAt(0);
System.Collections.IEnumerator rows = sheet.GetRowEnumerator();

DataTable dt = new DataTable();
for (int j = 0; j < 5;j++)
{
    dt.Columns.Add(Convert.ToChar(((int)'A')+j).ToString());
}

while(rows.MoveNext())
{
    HSSFRow row = (HSSFRow)rows.Current;
    DataRow dr = dt.NewRow();

for (int i = 0; i < row.LastCellNum; i++)
    {
        HSSFCell cell = row.GetCell(i);

if (cell ==
null)
        {
            dr[i] = null;
        }
        else

{

dr[i] = cell.ToString();

}

}

dt.Rows.Add(dr);

}

是不是很简单,呵呵!

当然,如果你要对某个特定的单元格类型做特殊处理,可以通过判HSSFCell.CellType来解决,比如下面的代码:

switch(cell.CellType)
        {
            case HSSFCellType.BLANK:
                dr[i] = "[null]";
                break;
            case HSSFCellType.BOOLEAN:
                dr[i] =cell.BooleanCellValue;
                break;
            case HSSFCellType.NUMERIC:
                dr[i] =cell.ToString();    //This
is a trick to get the correct value of the cell.NumericCellValue will
return a numeric value no matter the cell value is a dateor a number.

break;
            case HSSFCellType.STRING:
                dr[i] =cell.StringCellValue;
                break;
            case HSSFCellType.ERROR:
                dr[i] = cell.ErrorCellValue;
                break;
            case HSSFCellType.FORMULA:
            default:
                dr[i] = "="+cell.CellFormula;
                break;
        }

这里只是举个简单的例子。

完整代码下载:http://files.cnblogs.com/tonyqus/ImportXlsToDataTable.zip

NPOI读取Excel案例的更多相关文章

  1. NPOI读取Excel帮助类,支持xls与xlsx,实现公式解析,空行的处理

    NPOI读取Excel(2003或者2010)返回DataTable.支持公式解析,空行处理. /// <summary>读取excel /// 默认第一行为表头 /// </sum ...

  2. NPOI读取Excel表格类

    public class NPOIHelper    {        private HSSFWorkbook workbook;        public static IWorkbook Lo ...

  3. 使用NPOI读取Excel数据到DataTable

    如今XML文件的存储格式大行其道,可是也不是适用于全部情况,非常多单位的数据交换还是使用Excel的形式.这就使得我们须要读取Excel内的数据.载入到程序中进行处理.可是如何有效率的读取,如何使程序 ...

  4. NPOI读取Excel遇到的坑

    NPOI是POI的.NET版本.POI是用Java写成的库,能帮助用户在没有安装Office环境下读取Office2003-2007文件.NPOI在.NET环境下使用,能读写Excel/Word文件. ...

  5. 使用NPOI读取Excel出错

    使用NPOI读取Excel出错,错误信息:java.io.IOException: Invalid header signature; read 4503608217567241, expected ...

  6. asp.net 使用NPOI读取excel文件

    asp.net 使用NPOI读取excel文件内容 NPOI下载地址:NPOI public class ExcelHelper { /// <summary> /// 读取Excel文件 ...

  7. .NET Core 使用NPOI读取Excel返回泛型List集合

    我是一名 ASP.NET 程序员,专注于 B/S 项目开发.累计文章阅读量超过一千万,我的博客主页地址:https://www.itsvse.com/blog_xzz.html 网上有很多关于npoi ...

  8. 使用NPOI读取Excel数据并写入SQLite

    首先,我们来建一个数据库,我们就叫Hello.db(不一定是db后缀,你可以sqlite,sqlite3,db3)都可以作为识别,然后往里面建一个空的表格,如下图所示 然后建一个Excel表格,往表格 ...

  9. 使用NPOI读取Excel表格内容并进行修改

    前言 网上使用NPOI读取Excel文件的例子现在也不少,本文就是参考网上大神们的例子进行修改以适应自己需求的. 参考博文 http://www.cnblogs.com/restran/p/38894 ...

随机推荐

  1. javascript中的sort()方法

    现在在学习javascript中,发现sort()函数是有点奇怪的东西(可能是本人水平的问题-_-!),于是就在这里记录一下自己找到的东西吧.sort()这个方法的参数很奇怪,必须是函数,但也是可选参 ...

  2. 64位Win8系统下安装Oracle12c

    经过3个小时的折腾,终于在64位win8系统下成功安装了Oracle 12c.这篇文章主要把安装过程中遇到的一些问题总结一下,以便帮助后来人参考. 首先我把我的机器的主要配制情况列举出来: 1. 系统 ...

  3. C#使用oledb方式将excel数据导入到datagridview后数据被截断为 255 个字符

    问题描述:在使用oledb方式将excel数据导入到datagridview中,在datagridview单元格中的数据没有显示全,似乎只截取了数据源中的一段 解决方案:1.关于该问题,微软官方答案: ...

  4. JSFunction-Javascript常用函数库

    最近正在整理书写常用的Javascript函数库,此函数库近期会持续更新 JSFunction 这里可以找到你经常想要使用的js函数,我正在努力完善它 希望它对你有所帮助 相信代码是优雅的舞者.--北 ...

  5. Delphi窗体中禁用最大化按钮

    第一种方法是设置窗体的BorderIcons/biMaximize属性为False,这种方法仅让窗体的最大化按钮灰掉: 第二种方法是设置窗体的BorderStyle属性为bsDialog,这种方法使最 ...

  6. RHEL 6.1字符界面无法登录SSH却能登录

    1.具体版本: 2.具体现象: 每次输入用户名密码登录之后又跳到这个界面.但是用ssh却可以登录. 3.查看日志 [root@localhost ~]# tail -f /var/log/secure ...

  7. Web程序发布后显示个性化图标

    采用Tomcat发布程序后,浏览器上默认显示程序的图标是Tomcat图标.如下图所示: 需要显示自己个性化的图标,比如,这里显示一个图标. 只需要如下三步设置即可. 将制作的ico图标放在程序的根目录 ...

  8. C语言之指针

    以32为系统为例. 1.指针与地址指针是一种变量,保存了所指向对象的地址.1.1 定义int i = 10;int *p = &i; //定义了一个指针p,它指向一个int型的变量&是 ...

  9. Timer组件

    1.常用属性 Interval 用于获取或设置Timer组件Tick事件发生的时间间隔,属性值不能小于1 制作左右飘摇窗体 private void timer1_Tick(object sender ...

  10. 【Bean】 这才是bean,一直没仔细看

    EJB是Enterprise Java Bean的缩写,一个Bean扮演着应用程序素材的角色.它包含有一个functional interface,一个life-cycle interface,以及一 ...