Java POI操作Excel(User Model)

该文章为本系列的第一篇
第二篇为 : Java POI操作Excel(Event Model)
第三篇为 : Java POI操作Excel(Event User Model)
第四篇为 : 使用POI封装一个轻量级Excel解析框架

前言

在B端系统中,通常都会提供Excel导入导出数据的功能.所以使用Java对Excel进行操作是每个Java Web工程师必备的技能.而在Java领域,Apache POI是优秀的Excel操作库.这篇文章开始,我们就使用POI一步一步的进行Excel的操作,到最后自制一个简单的基于POI的Excel解析框架.

POI简介

POI-HSSF and POI-XSSF - Java API To Access Microsoft Excel Format Files

HSSF is the POI Project's pure Java implementation of the Excel '97(-2007) file format. XSSF is the POI Project's pure Java implementation of the Excel 2007 OOXML (.xlsx) file format.

POI针对目前存在的两种版本的Excel有不同的实现方式.而对于相同版本的Excel又分为Dom解析和Sax解析两种.而这两种在内存使用,性能各方面均有不同.官方文档中给出了具体的比较,如下图前四列.第五列则是对Excel2007版本提供的节约内存的导出方式进行了介绍.

poi_api_type.png

POI UserModel

根据上面的表格我们可以看到,所谓的UserModel实际上就类似于Dom方式的解析.学过Xml解析的朋友都会知道所谓的Dom解析就是将文件全部读入内存,对文件内部的结构进行建模成一颗Dom树的过程.接下来我们看一下POI对Excel的建模的Dom树是什么结构的.

POI 官网Demo

http://poi.apache.org/spreadsheet/quick-guide.html

官网中对这个页面的标题是 Busy Developers' Guide to HSSF and XSSF Features

所以我们通过这个网页Demo的学习,即可完成对POI的入门.

快速入门

开发环境

Java版本 :1.8.0_40
Maven版本:3.3.9
POI版本 :3.15

创建一个工作簿(Workbook)

POI中使用Workbook对Excel对象进行建模.

public class Demo01 {
    public static void main(String[] args) throws Exception {
        Workbook excel1997 = new HSSFWorkbook(); // excel 1997
        FileOutputStream fileOut = new FileOutputStream("workbook.xls");
        excel1997.write(fileOut);
        fileOut.close();

        Workbook excel2007 = new XSSFWorkbook(); // excel 2007
        fileOut = new FileOutputStream("workbook.xlsx");
        excel2007.write(fileOut);
        fileOut.close();
    }
}

打开创建的Excel

empty-excel.png

Workbook对象是UserModel解析方式中整个Dom树的根对象.而Workbook类本身是一个接口,规范了Workbook对象的基本功能.所以除非我们是要使用特定版本Excel的特性,一般都是面向Workbook接口编程.

创建一个工作表(sheet)

public static void main(String[] args) throws Exception {
        Workbook wb = new HSSFWorkbook();
        Sheet sheet1 = wb.createSheet("new sheet");
        Sheet sheet2 = wb.createSheet("second sheet");

        // Note that sheet name is Excel must not exceed 31 characters
        // and must not contain any of the any of the following characters:
        // 0x0000
        // 0x0003
        // colon (:)
        // backslash (\)
        // asterisk (*)
        // question mark (?)
        // forward slash (/)
        // opening square bracket ([)
        // closing square bracket (])

        // You can use org.apache.poi.ss.util.WorkbookUtil#createSafeSheetName(String nameProposal)}
        // for a safe way to create valid names, this utility replaces invalid characters with a space (' ')
        String safeName = WorkbookUtil.createSafeSheetName("[O'Brien's sales*?]"); // returns " O'Brien's sales   "
        Sheet sheet3 = wb.createSheet(safeName);

        FileOutputStream fileOut = new FileOutputStream("workbook02.xls");
        wb.write(fileOut);
        fileOut.close();
    }

打开创建的Excel

create-sheet.png

Sheet对象是Workbook对象下的一级对象,代表工作表.而通过上面的程序Demo我们已经可以知道在创建Sheet的时候,要注意的工作表的命名约束.以及如何使用安全的方式创建工作表.

创建单元格

public static void main(String[] args) throws Exception {
        Workbook wb = new HSSFWorkbook();
        //Workbook wb = new XSSFWorkbook();
        CreationHelper createHelper = wb.getCreationHelper();
        Sheet sheet = wb.createSheet("new sheet");

        // Create a row and put some cells in it. Rows are 0 based.
        Row row = sheet.createRow((short)0);
        // Create a cell and put a value in it.
        Cell cell = row.createCell(0);
        cell.setCellValue(1);

        // Or do it on one line.
        row.createCell(1).setCellValue(1.2);
        row.createCell(2).setCellValue(
                createHelper.createRichTextString("This is a string"));
        row.createCell(3).setCellValue(true);

        // Write the output to a file
        FileOutputStream fileOut = new FileOutputStream("workbook03.xls");
        wb.write(fileOut);
        fileOut.close();
 }

打开创建的Excel

create-cell.png

通过代码我们可以知道Sheet下一级的对象不是Cell而是Row,而Row的下一级对象是Cell.在部分代码很好理解.我们重点介绍一下这个RichTextString.Excel中的字符串,都会存在一个Table(数组)中,而在解析Excel的时候我们会发现解析到的文本类型的单元格的value是数字,而这个数字实际上就是该文本在RichText Table中的下标.

小结

至此,我们了解了POI对Excel操作的UserModel时Dom树的整体结构.如下图
而我们在解析Excel的时候,即可按照这种方式,从上到下,对我们需要的数据进行解析.


usermodel-domtree.png

解析

要解析的Excel

to-parse.png

编码

public static void main(String[] args) throws Exception {
    InputStream inp = null;
    try {
        inp = new FileInputStream("workbook04.xls");
        Workbook wb = WorkbookFactory.create(inp);
        Sheet sheet = wb.getSheetAt(0);
        Iterator<Row> rowIterator = sheet.rowIterator();
        while (rowIterator.hasNext()) {
            Row r = rowIterator.next();
            if (r == null) {
                System.out.println("Empty Row");
                continue;
            }
            for (int i = r.getFirstCellNum(); i < r.getLastCellNum(); i++) {
                Cell cell = r.getCell(i);
                String cellValue = "";
                switch (cell.getCellType()) {
                    case Cell.CELL_TYPE_STRING:
                        cellValue = cell.getRichStringCellValue().getString();
                        break;
                    case Cell.CELL_TYPE_NUMERIC:
                        if (DateUtil.isCellDateFormatted(cell)) {
                            cellValue = cell.getDateCellValue().toString();
                        } else {
                            cellValue = String.valueOf(cell.getNumericCellValue());
                        }
                        break;
                    case Cell.CELL_TYPE_BOOLEAN:
                        cellValue = String.valueOf(cell.getBooleanCellValue());
                        break;
                    case Cell.CELL_TYPE_FORMULA:
                        cellValue = String.valueOf(cell.getCellFormula());
                        break;
                    case Cell.CELL_TYPE_BLANK:
                        break;
                    default:
                }
                System.out.println("CellNum:" + i + " => CellValue:" + cellValue);
            }
        }
    } finally {
        if (inp != null) {
            inp.close();
        }
    }
}

输出结果

CellNum:0 => CellValue:1.0
CellNum:1 => CellValue:Sun Jul 16 00:00:00 CST 2017
CellNum:2 => CellValue:This is a String

小结

  • 使用WorkbookFactory来创建Workbook.从而不引入具体的Workbook实现.达到解耦的效果
  • 遍历Row和Cell的时候既可以使用Iterator,也可以使用for循环的方式.其中实际有数据的是获取到的最后一行(或一列)的前一行(一列)
  • 针对不同类型的CellType,取值方式并不相同.要使用恰当的方式.

总结

这篇文章作为Excel解析的第一篇,对POI进行了简单的介绍.然后通过几个简单小例子对POI的UserModel进行了分析与讲解.总体来说,UserModel方式解析Excel比较简单.但是作为代价,这种方式对内存的占用是不小的.这也是我们在对技术选型时要考虑的因素.

本文只作为Excel解析的入门,并不能涉及UserModel的方方面面,更多内容还需要去官网查看Demo进行学习.而使用文档进行学习也是程序员的必备技能之一.需要我们不断的训练自己这方面的能力.

参考文档

Busy Developers' Guide to HSSF and XSSF Features

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • POI操作Excel Excel简介一个excel文件就是一个工作簿workbook,一个工作簿中可以创建多张工作...
    灰气球阅读 4,625评论 2 48
  • 使用首先需要了解他的工作原理 1.POI结构与常用类 (1)创建Workbook和Sheet (2)创建单元格 (...
    长城ol阅读 8,258评论 2 25
  • 实习第二周 No.2 项目功能里要求能够将展示的报表导出excel,因为报表的数据都是动态从list传进来的,所...
    苏筱筑阅读 2,261评论 2 7
  • 转自链接 目录 1.认识NPOI 2.使用NPOI生成xls文件 2.1创建基本内容 2.1.1创建Workboo...
    腿毛裤阅读 9,918评论 1 3
  • ——从《后会无期》的一个细节说起 《后会无期》有很多有趣的细节值得玩味。印象最深的是贾樟柯大佬出场的那一段。下车后...
    刘雨薇阅读 445评论 2 2