Java POI操作Excel(User Model)

該文章為本系列的第一篇
第二篇為 : Java POI操作Excel(Event Model)
第三篇為 : Java POI操作Excel(Event User Model)
第四篇為 : 使用POI封裝一個(gè)輕量級(jí)Excel解析框架

前言

在B端系統(tǒng)中,通常都會(huì)提供Excel導(dǎo)入導(dǎo)出數(shù)據(jù)的功能.所以使用Java對(duì)Excel進(jìn)行操作是每個(gè)Java Web工程師必備的技能.而在Java領(lǐng)域,Apache POI是優(yōu)秀的Excel操作庫.這篇文章開始,我們就使用POI一步一步的進(jìn)行Excel的操作,到最后自制一個(gè)簡(jiǎn)單的基于POI的Excel解析框架.

POI簡(jiǎn)介

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針對(duì)目前存在的兩種版本的Excel有不同的實(shí)現(xiàn)方式.而對(duì)于相同版本的Excel又分為Dom解析和Sax解析兩種.而這兩種在內(nèi)存使用,性能各方面均有不同.官方文檔中給出了具體的比較,如下圖前四列.第五列則是對(duì)Excel2007版本提供的節(jié)約內(nèi)存的導(dǎo)出方式進(jìn)行了介紹.

poi_api_type.png

POI UserModel

根據(jù)上面的表格我們可以看到,所謂的UserModel實(shí)際上就類似于Dom方式的解析.學(xué)過Xml解析的朋友都會(huì)知道所謂的Dom解析就是將文件全部讀入內(nèi)存,對(duì)文件內(nèi)部的結(jié)構(gòu)進(jìn)行建模成一顆Dom樹的過程.接下來我們看一下POI對(duì)Excel的建模的Dom樹是什么結(jié)構(gòu)的.

POI 官網(wǎng)Demo

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

官網(wǎng)中對(duì)這個(gè)頁面的標(biāo)題是 Busy Developers' Guide to HSSF and XSSF Features

所以我們通過這個(gè)網(wǎng)頁Demo的學(xué)習(xí),即可完成對(duì)POI的入門.

快速入門

開發(fā)環(huán)境

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

創(chuàng)建一個(gè)工作簿(Workbook)

POI中使用Workbook對(duì)Excel對(duì)象進(jìn)行建模.

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();
    }
}

打開創(chuàng)建的Excel

empty-excel.png

Workbook對(duì)象是UserModel解析方式中整個(gè)Dom樹的根對(duì)象.而Workbook類本身是一個(gè)接口,規(guī)范了Workbook對(duì)象的基本功能.所以除非我們是要使用特定版本Excel的特性,一般都是面向Workbook接口編程.

創(chuàng)建一個(gè)工作表(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();
    }

打開創(chuàng)建的Excel

create-sheet.png

Sheet對(duì)象是Workbook對(duì)象下的一級(jí)對(duì)象,代表工作表.而通過上面的程序Demo我們已經(jīng)可以知道在創(chuàng)建Sheet的時(shí)候,要注意的工作表的命名約束.以及如何使用安全的方式創(chuàng)建工作表.

創(chuàng)建單元格

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();
 }

打開創(chuàng)建的Excel

create-cell.png

通過代碼我們可以知道Sheet下一級(jí)的對(duì)象不是Cell而是Row,而Row的下一級(jí)對(duì)象是Cell.在部分代碼很好理解.我們重點(diǎn)介紹一下這個(gè)RichTextString.Excel中的字符串,都會(huì)存在一個(gè)Table(數(shù)組)中,而在解析Excel的時(shí)候我們會(huì)發(fā)現(xiàn)解析到的文本類型的單元格的value是數(shù)字,而這個(gè)數(shù)字實(shí)際上就是該文本在RichText Table中的下標(biāo).

小結(jié)

至此,我們了解了POI對(duì)Excel操作的UserModel時(shí)Dom樹的整體結(jié)構(gòu).如下圖
而我們?cè)诮馕鯡xcel的時(shí)候,即可按照這種方式,從上到下,對(duì)我們需要的數(shù)據(jù)進(jìn)行解析.


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();
        }
    }
}

輸出結(jié)果

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

小結(jié)

  • 使用WorkbookFactory來創(chuàng)建Workbook.從而不引入具體的Workbook實(shí)現(xiàn).達(dá)到解耦的效果
  • 遍歷Row和Cell的時(shí)候既可以使用Iterator,也可以使用for循環(huán)的方式.其中實(shí)際有數(shù)據(jù)的是獲取到的最后一行(或一列)的前一行(一列)
  • 針對(duì)不同類型的CellType,取值方式并不相同.要使用恰當(dāng)?shù)姆绞?

總結(jié)

這篇文章作為Excel解析的第一篇,對(duì)POI進(jìn)行了簡(jiǎn)單的介紹.然后通過幾個(gè)簡(jiǎn)單小例子對(duì)POI的UserModel進(jìn)行了分析與講解.總體來說,UserModel方式解析Excel比較簡(jiǎn)單.但是作為代價(jià),這種方式對(duì)內(nèi)存的占用是不小的.這也是我們?cè)趯?duì)技術(shù)選型時(shí)要考慮的因素.

本文只作為Excel解析的入門,并不能涉及UserModel的方方面面,更多內(nèi)容還需要去官網(wǎng)查看Demo進(jìn)行學(xué)習(xí).而使用文檔進(jìn)行學(xué)習(xí)也是程序員的必備技能之一.需要我們不斷的訓(xùn)練自己這方面的能力.

參考文檔

Busy Developers' Guide to HSSF and XSSF Features

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末边锁,一起剝皮案震驚了整個(gè)濱河市誊册,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荐健,老刑警劉巖酱畅,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異江场,居然都是意外死亡纺酸,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門址否,熙熙樓的掌柜王于貴愁眉苦臉地迎上來餐蔬,“玉大人,你說我怎么就攤上這事在张∮煤” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵帮匾,是天一觀的道長(zhǎng)啄骇。 經(jīng)常有香客問我,道長(zhǎng)瘟斜,這世上最難降的妖魔是什么缸夹? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮螺句,結(jié)果婚禮上虽惭,老公的妹妹穿的比我還像新娘。我一直安慰自己蛇尚,他們只是感情好芽唇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著取劫,像睡著了一般匆笤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谱邪,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天炮捧,我揣著相機(jī)與錄音,去河邊找鬼惦银。 笑死咆课,一個(gè)胖子當(dāng)著我的面吹牛末誓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播书蚪,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼喇澡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了善炫?” 一聲冷哼從身側(cè)響起撩幽,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤库继,失蹤者是張志新(化名)和其女友劉穎箩艺,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體宪萄,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艺谆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拜英。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片静汤。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖居凶,靈堂內(nèi)的尸體忽然破棺而出虫给,到底是詐尸還是另有隱情,我是刑警寧澤侠碧,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布抹估,位于F島的核電站,受9級(jí)特大地震影響弄兜,放射性物質(zhì)發(fā)生泄漏药蜻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一替饿、第九天 我趴在偏房一處隱蔽的房頂上張望语泽。 院中可真熱鬧,春花似錦视卢、人聲如沸踱卵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽惋砂。三九已至,卻和暖如春蝶俱,著一層夾襖步出監(jiān)牢的瞬間班利,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工榨呆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留罗标,地道東北人庸队。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像闯割,于是被迫代替她去往敵國(guó)和親彻消。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • POI操作Excel Excel簡(jiǎn)介一個(gè)excel文件就是一個(gè)工作簿workbook宙拉,一個(gè)工作簿中可以創(chuàng)建多張工作...
    灰氣球閱讀 4,705評(píng)論 2 48
  • 使用首先需要了解他的工作原理 1.POI結(jié)構(gòu)與常用類 (1)創(chuàng)建Workbook和Sheet (2)創(chuàng)建單元格 (...
    長(zhǎng)城ol閱讀 8,409評(píng)論 2 25
  • 實(shí)習(xí)第二周 No.2 項(xiàng)目功能里要求能夠?qū)⒄故镜膱?bào)表導(dǎo)出excel宾尚,因?yàn)閳?bào)表的數(shù)據(jù)都是動(dòng)態(tài)從list傳進(jìn)來的,所...
    蘇筱筑閱讀 2,341評(píng)論 2 7
  • 轉(zhuǎn)自鏈接 目錄 1.認(rèn)識(shí)NPOI 2.使用NPOI生成xls文件 2.1創(chuàng)建基本內(nèi)容 2.1.1創(chuàng)建Workboo...
    腿毛褲閱讀 10,481評(píng)論 1 3
  • ——從《后會(huì)無期》的一個(gè)細(xì)節(jié)說起 《后會(huì)無期》有很多有趣的細(xì)節(jié)值得玩味敬鬓。印象最深的是賈樟柯大佬出場(chǎng)的那一段淹朋。下車后...
    劉雨薇閱讀 461評(píng)論 2 2