Java解析Excel例項解析

ZhangJianIsAStark發表於2017-03-09

最近有些配置APN的工作,需要將Excel中的資訊,配置成Android apns-conf.xml中的樣式。
作為一個程式設計師,我怎麼可能一行行的用眼睛看,然後用手去配置了!
於是,我決定利用Apache POI的支援庫,用java程式解析Excel表,
然後按指定格式生成輸出檔案。

這篇部落格主要記錄一下Java解析Excel的基本方法,結尾附上demo。


首先附上Apache POI庫的下載地址Apache POI - Download Release Artifacts
選擇合適的庫後,會自動跳轉到映象地址。
我的demo是基於poi-3.16-beta2寫的,不過並沒有使用什麼高深介面,因此程式碼應該是通用的。

匯入依賴庫後,主要的工作其實就是明白依賴庫中定義的Excel物件了,這裡盜一張圖:
Java解析Excel例項解析

如圖所示:
每一個Excel檔案都將被解析成一個WorkBook物件;
Excel的每一頁都將被解析成一個Sheet物件;
然後,Excel中的每一行都是一個Row物件,
每一個單元格都是一個Cell物件。

對這些基本概念有了一些基本瞭解後,就可以開始上例項了。

Java解析Excel例項解析

如上圖所示,為Excel中內容的基本格式,即一些APN需要的資訊。
為了方便我解析,我稍微修改了一些格式,將標題欄中每一項的首字母大寫(與Java解析Excel無關)。

Java入口函式如下:

public class MainEntrance {
    public static void main(String[] args) {
        //由於Java解析Excel不可避免的與檔案格式耦合
        //因此,我只能寫一個特質化的工具,而不是寫個模板
        ApnExcelParseTool excelParseTool = new ApnExcelParseTool();

        //傳入原始檔地址
        excelParseTool.setFilePath("/home/zhangjian/Desktop/all_apn_together.xlsx");

        try {
            //解析Excel得到Workbook物件
            Workbook workbook = excelParseTool.initWorkBook();

            //每一行具體資料,都將變成一個ApnModel
            List<ApnModel> outData = new ArrayList<>();

            if (workbook != null) {
                //將workbook物件,解析成ApnModel
                excelParseTool.parseWorkbook(workbook, outData);
            }

            if (outData.size() > 0) {
                //將所有的ApnModel寫入到輸出檔案中
                new ApnWriteTool().write("/home/zhangjian/Desktop/apns-conf.xml", outData);
            }
        } catch (IOException e) {
            System.out.println(e.toString());
        }
    }
}

整個Java主函式的邏輯還是很簡單的。


現在我們看看核心類ApnExcelParseTool中的內容,首先看看獲取Workbook相關的程式碼:

class ApnExcelParseTool {
    private String mFilePath;

    //儲存原始檔內容
    void setFilePath(String filePath) {
        mFilePath = filePath;
    }

    private static final String SUFFIX_2003 = ".xls";
    private static final String SUFFIX_2007 = ".xlsx";

    Workbook initWorkBook() throws IOException {
        File file = new File(mFilePath);
        InputStream is = new FileInputStream(file);

        Workbook workbook = null;
        //根據字尾,得到不同的Workbook子類,即HSSFWorkbook或XSSFWorkbook
        if (mFilePath.endsWith(SUFFIX_2003)) {
            workbook = new HSSFWorkbook(is);
        } else if (mFilePath.endsWith(SUFFIX_2007)) {
            workbook = new XSSFWorkbook(is);
        }

        return workbook;
    }
....................

得到Workbook後,就可以開始進一步解析了:

.......................
    void parseWorkbook(Workbook workbook, List<ApnModel> apnModelList) {
        int numOfSheet = workbook.getNumberOfSheets();

        //依次解析每一個Sheet
        for (int i = 0; i < numOfSheet; ++i) {
            Sheet sheet = workbook.getSheetAt(i);
            parseSheet(sheet, apnModelList);
        }
    }

    //儲存需要呼叫的ApnModel中的方法
    private List<Method> mUsedMethod;

    private void parseSheet(Sheet sheet, List<ApnModel> apnModelList) {
        Row row;

        int count = 0;

        //利用迭代器,取出每一個Row
        Iterator<Row> iterator = sheet.iterator();
        while(iterator.hasNext()) {
            row = iterator.next();

            //由於第一行是標題,因此這裡單獨處理
            if (count == 0) {
                mUsedMethod = new ArrayList<>();
                parseRowAndFindMethod(row);
            } else {
                //其它行都在這裡處理
                parseRowAndFillData(row, apnModelList);
            }

            ++count;
        }
    }

    private void parseRowAndFindMethod(Row row) {
        //利用parseRow處理每一行,得到每個cell中的String
        List<String> rst = parseRow(row);

        String methodName;
        try {
            //根據String得到需要呼叫的ApnModel中的方法
            //由於自己在ApnModel中定義的方法均是類似setMcc、setMnc等
            //因此才在一開始,將標題欄中每一項大寫
            for (String str : rst) {
                methodName = "set" + str;
                //反射拿到method
                mUsedMethod.add(
                        ApnModel.class.getDeclaredMethod(methodName, String.class));
            }
        } catch (NoSuchMethodException e) {
            System.out.println(e.toString());
        }

    }

    //開始解析具體的資料
    private void parseRowAndFillData(Row row, List<ApnModel> apnModelList) {
        //同樣利用parseRow得到具體每一行的資料
        List<String> rst = parseRow(row);

        ApnModel apnModel = new ApnModel();

        //這裡主要debug一下,避免由於Excel的格式可能不太對
        //使得每一行的資料解析地不太對
        if (mUsedMethod.size() != rst.size()) {
            System.out.println("WTF, size not right");
        } else {
            //利用反射,將資料填充到具體的ApnModel
            try {
                for (int i = 0; i < mUsedMethod.size(); ++i) {
                    mUsedMethod.get(i).invoke(apnModel, rst.get(i));
                }

                //儲存到輸出結果中
                apnModelList.add(apnModel);
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
    }

    //這裡是解析每一行的程式碼
    private List<String> parseRow(Row row) {
        List<String> rst = new ArrayList<>();

        Cell cell;

        //利用迭代器得到每一個cell
        Iterator<Cell> iterator = row.iterator();
        while (iterator.hasNext()) {
            cell = iterator.next();

            //定義每一個cell的資料型別
            cell.setCellType(CellType.STRING);

            //取出cell中的value
            rst.add(cell.getStringCellValue());
        }

        return rst;
    }
.................

以上就是Java解析Excel範例的核心程式碼了。

之後的工作就是將ApnModel中儲存的資料,按照需要的格式寫入到輸出檔案了。
這部分程式碼比較粗糙,也與主題無關,就不直接貼到部落格上了。

最後的輸出結果類似於。與原生的格式一致了:
Java解析Excel例項解析

這裡唯一要注意的是,要保證Excel的格式正確。
單元格的內容可以是空白的,因此要保證Excel中僅有資料佔有了實際的內容。
Java解析Excel例項解析
如上圖所示,資料部分可以空白,但非資料的紅色部分就不要有內容了。

最後,demo地址如下:
https://github.com/ZhangJianIsAStark/ExcelParseDemo
這裡我只上傳了原始碼,還需要自己配置Apache POI jar包。

相關文章