Apache POI 之一:Excel文檔的讀取

Apache POI 是創(chuàng)建和維護操作各種符合Office Open XML(OOXML)標準和微軟的OLE 2復合文檔格式(OLE2)的Java API。用它可以使用Java讀取和創(chuàng)建,修改MS Excel文件.而且,還可以使用Java讀取和創(chuàng)建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解決方案(適用于Excel97-2008)虚循。

前言:依賴或下載

<!-- poi 依賴 -->
<dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi</artifactId>
   <version>3.16</version>
</dependency>

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.16</version>
</dependency>

或者在poi.apache.org下載jar包

本篇文章主要是演示Excel文檔的讀取處理猎物。
使用POI解析Excel有兩個需要注意的關(guān)鍵點:

  • 遍歷方式的區(qū)別(PhysicalNumber和Number)
  • 單元格不同格式的讀取

下面單獨說明一下秆吵。

POI遍歷方式的區(qū)別(PhysicalNumber和Number)

Excel文檔結(jié)構(gòu)分為整個文檔(Workbook)淮椰、分頁(Sheet)、行(Row)纳寂、單元格(Cell)四個類來描述主穗,而遍歷整個Excel也是通過層層遍歷到單元格的方式,但是方式略有不同烈疚。如POI提供了獲取行數(shù)的方法為getPhysicalNumberOfRows黔牵,而這里physical的含義就是去除了空行的數(shù)量聪轿,因此只有保證沒有空行的情況下才能使用這個數(shù)量來遍歷全部行爷肝。去除空行的遍歷:

//行數(shù)
int rowNum=sheet.getPhysicalNumberOfRows();
if(rowNum<1) continue;

// 從第2(r=1)行取出,第一行默認為標題行
rowNum+=1;

//遍歷
for(int r=1;r<rowNum;r++)
{
    Row row=sheet.getRow(r);
  
    //其他處理
}

但是陆错,在下一層即遍歷Cell單元格的時候如果還使用類似的getPhysicalNumberOfCells來獲取數(shù)量遍歷則可能出現(xiàn)錯誤灯抛,因為獲取到的數(shù)量是去除了空格的單元格數(shù)量,而單元格的內(nèi)容很可能是空的音瓷,所以這里就要使用一種可以遍歷全部單元格的遍歷方式:

// 循環(huán)取出每行的列數(shù)对嚼,其實是最后一列的列數(shù)
int cellNum=row.getLastCellNum();
// 遍歷
for(int c=0;c<cellNum;c++)
{
    // 取出每列值
    Cell cell=row.getCell(c);
    
    //其他處理
}

單元格不同格式的讀取

POI解析Cell的類型分為了字符串、數(shù)字绳慎、公式以及布爾四種類型:

  • 其中纵竖,字符串通過getRechStringCellValue().toString()來獲取即可;
  • 而數(shù)字和公式在Excel中實際儲存的都是Double類型杏愤;
  • 布爾類型直接通過getBooleanCellValue()獲取靡砌。
  • 比較特殊是日期類型,日期類型實際cellType是數(shù)字珊楼,但是直接讀取數(shù)字則不是想要的格式通殃。為此,POI提供了一個方法(org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))來判斷是否為日期厕宗,如果為日期格式則使用cell的getDateCellValue方法獲取就可以得到Excel里格式化后的日期內(nèi)容画舌。

工具使用代碼示例

(我這里的業(yè)務(wù)要求是只取部分需要的列里的值,而非全部列里的值導入已慢。)

package pb.utils;

import org.apache.poi.ss.usermodel.*;

import java.io.File;
import java.util.*;

/**
 * Excel導入讀取
 */
public class ExcelUtils
{
    /**
     * 動態(tài)解析Excel文件曲聂,并返回指定的對象列表
     *
     * @param excelFile
     * @param patternKey 匹配使用的主鍵名
     * @param pattern    全部匹配值
     * @param columnMap  需要獲取的標題與字段名的對應(yīng),如顯示名稱->name佑惠;包含主鍵列
     * @return
     */
    public static Map<String,LinkedHashMap<String,Object>> resolveExcel(File excelFile,String patternKey,Set<String> pattern,Map<String,String> columnMap) throws Exception
    {
        //記錄結(jié)果
        Map<String,LinkedHashMap<String,Object>> result=new HashMap<>();
        //載入文件
        Workbook workbook=WorkbookFactory.create(excelFile);

        //記錄當前標題與列位置的映射
        Map<String,String> titleMap=new LinkedHashMap<>();

        //遍歷所有Sheet頁
        int pageNum=workbook.getNumberOfSheets();
        for(int page=0;page<pageNum;page++)
        {
            //獲取Sheet
            Sheet sheet=workbook.getSheetAt(page);

            //遍歷全部非空行
            Iterator<Row> rowItr=sheet.rowIterator();
            int rowNum=0;
            while(rowItr.hasNext())
            {
                //獲取行
                Row row=rowItr.next();
                //記錄數(shù)據(jù)
                LinkedHashMap<String,Object> map=new LinkedHashMap<>();

                //遍歷本行全部列(包括空列)
                int colNum=row.getLastCellNum();
                for(int index=0;index<colNum;index++)
                {
                    //獲取單元格
                    Cell cell=row.getCell(index);
                    //獲取單元格內(nèi)容
                    Object value=getCellValue(cell);

                    //第一行為標題行句葵,記錄標題和位置索引的映射
                    if(rowNum==0)
                    {
                        String title=value+"";
                        if(columnMap.containsKey(title))
                            titleMap.put(index+"",title);
                    }
                    //非標題行厕鹃,根據(jù)指定columnMap和PatternKey查找記錄
                    else
                    {
                        //需要的內(nèi)容
                        if(!titleMap.containsKey(index+"")) continue;
                        map.put(columnMap.get(titleMap.get(index+"")),value);
                    }
                }

                //驗證是否記錄此行
                if(pattern.contains(map.get(patternKey)+""))
                {
                    result.put(map.get(patternKey)+"",map);
                }

                rowNum++;
            }
        }

        return result;
    }

    /**
     * 依據(jù)Excel中Cell類型讀取不同的值
     *
     * @param cell
     * @return String/Double/Date/boolean/null
     */
    public static Object getCellValue(Cell cell)
    {
        Object result=null;

        //獲取類型
        int type=cell.getCellType();
        //根據(jù)不同類型處理
        switch(type)
        {
            //字符串
            case Cell.CELL_TYPE_STRING:
            {
                result=cell.getRichStringCellValue().toString().trim();
                break;
            }
            //數(shù)字(Double)
            case Cell.CELL_TYPE_NUMERIC:
            //公式(Double)
            case Cell.CELL_TYPE_FORMULA:
            {
                //日期類型判斷
                //日期類型
                if(org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell))
                {
                    result=cell.getDateCellValue();
                }
                //普通數(shù)字
                else
                {
                    result=new Double(cell.getNumericCellValue());
                }
                break;
            }
            //布爾
            case Cell.CELL_TYPE_BOOLEAN:
            {
                result=cell.getBooleanCellValue();
                break;
            }
            //其他
            default:
        }

        return result;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市乍丈,隨后出現(xiàn)的幾起案子剂碴,更是在濱河造成了極大的恐慌,老刑警劉巖轻专,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忆矛,死亡現(xiàn)場離奇詭異,居然都是意外死亡请垛,警方通過查閱死者的電腦和手機催训,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宗收,“玉大人漫拭,你說我怎么就攤上這事』旎” “怎么了采驻?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長匈勋。 經(jīng)常有香客問我礼旅,道長,這世上最難降的妖魔是什么洽洁? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任痘系,我火速辦了婚禮,結(jié)果婚禮上饿自,老公的妹妹穿的比我還像新娘汰翠。我一直安慰自己,他們只是感情好昭雌,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布复唤。 她就那樣靜靜地躺著,像睡著了一般城豁。 火紅的嫁衣襯著肌膚如雪苟穆。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天唱星,我揣著相機與錄音雳旅,去河邊找鬼。 笑死间聊,一個胖子當著我的面吹牛攒盈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播哎榴,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼型豁,長吁一口氣:“原來是場噩夢啊……” “哼僵蛛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起迎变,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤充尉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后衣形,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體驼侠,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年谆吴,在試婚紗的時候發(fā)現(xiàn)自己被綠了倒源。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡句狼,死狀恐怖笋熬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情腻菇,我是刑警寧澤胳螟,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站芜繁,受9級特大地震影響旺隙,放射性物質(zhì)發(fā)生泄漏绒极。R本人自食惡果不足惜骏令,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望垄提。 院中可真熱鬧榔袋,春花似錦、人聲如沸铡俐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吏够。三九已至,卻和暖如春滩报,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背捶枢。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留贰健,地道東北人胞四。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枚赡。 傳聞我的和親對象是個殘疾皇子卢肃,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

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

  • 使用首先需要了解他的工作原理 1.POI結(jié)構(gòu)與常用類 (1)創(chuàng)建Workbook和Sheet (2)創(chuàng)建單元格 (...
    長城ol閱讀 8,414評論 2 25
  • 轉(zhuǎn)自鏈接 目錄 1.認識NPOI 2.使用NPOI生成xls文件 2.1創(chuàng)建基本內(nèi)容 2.1.1創(chuàng)建Workboo...
    腿毛褲閱讀 10,496評論 1 3
  • POI操作Excel Excel簡介一個excel文件就是一個工作簿workbook,一個工作簿中可以創(chuàng)建多張工作...
    灰氣球閱讀 4,705評論 2 48
  • 實習第二周 No.2 項目功能里要求能夠?qū)⒄故镜膱蟊韺С鰁xcel,因為報表的數(shù)據(jù)都是動態(tài)從list傳進來的德谅,所...
    蘇筱筑閱讀 2,341評論 2 7
  • Apache POI 是用Java編寫的免費開源的跨平臺的 Java API愧驱,Apache POI提供API給Ja...
    玩味Orz閱讀 2,608評論 0 0