POI详解以及 Java 使用POI操作Excel


一. POI详解

1. 简介

Apache POI 简介是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office(Excel、WORD、PowerPoint、Visio等)格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“可怜的模糊实现”。
Apache官网:https://www.apache.org/
POI网址:http://poi.apache.org/
POI文档:http://poi.apache.org/apidocs/index.html
本项目中使用的是poi-3.17.jar,相对来说比较稳定,并且有对应版本的文档。

2.常用类介绍

Workbook类和HSSFWorkbook类、Sheet类 和 HSSFSheet类、Row类 和 HSSFRow类、Cell类和HSSFCell类是继承关系,

1)Workbook类

Workbook workbook = WorkbookFactory.create(new File(filePath)); // 根据已有的Excel文件创建工作簿
workbook.write(out); // 工作簿写入,不加这句无法更改Excel文件

2)HSSFWorkbook类

HSSFWorkbook wb= new HSSFWorkbook();// 生成新的Excel文件

HSSFWorkbook workbook= new HSSFWorkbook(new FileInputStream(path)); // 根据已有的Excel文件创建工作簿

3)Sheet类 和 HSSFSheet类

 Sheet sheet = wb.getSheetAt(sheetIndex); // 通过索引获得文件中指定sheet,从0开始
 Sheet sheet = wb.getSheetAt("sheet1"); // 通过sheet名获得文件中指定sheet
 Sheet sheet = wb.createSheet(String sheetname);  // 创建一个新的Sheet 
 HSSFSheet sheet = workbook.getSheetAt(sheetIndex); // 通过索引获得文件中指定sheet,从0开始
 HSSFSheet sheet = workbook.getSheetAt("sheet1"); // 通过sheet名获得文件中指定sheet
 HSSFSheet sheet = workbook.createSheet("sheet1"); // 创建一个新的Sheet 

 int RowNum =  sheet.getLastRowNum(); // 获得最大行数

 sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); //  合并单元格 

sheet.shiftRows(rowIndex, lastRowNo, n); // 插入某一行

4)Row类 和 HSSFRow类

 Row row = sheet.getRow(i); // 获得指定行
 HSSFRow row = sheet.getRow(i); 

 Row row = sheet.createRow(i); // 创建指定行
 HSSFRow row = sheet.createRow(i); // 创建指定行

 row.getCell(i); // 获得指定单元格

5)Cell类 和 HSSFCell类

cell.getRowIndex(); // 获取当前单元格的行数
cell.getColumnIndex(); // 获取当前单元格的列数
cell.setCellValue(""); // 给当前单元格赋值
cell.getRow() // 获取当前单元格所在的行对象

6)CellStyle类 和 HSSFCellStyle类

CellStyle style = wb.createCellStyle(); // 创建一个单元格格式对象
style.setFillForegroundColor(IndexedColors.PALE_BLUE.getIndex()); // 设置单元格填充颜色
style.setFillBackgroundColor(short bg);  //设置背景颜色
style.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 设置单元格画布格式
style.setWrapText(true); // 设置自动换行
style.setAlignment(HorizontalAlignment.CENTER); // 水平居中
style.setVerticalAlignment(VerticalAlignment.CENTER); // 垂直居中
font.setFontHeightInPoints((short) heigth); // 设置行高
style.setBorderBottom(BorderStyle.THIN); // 单元格边框
style.setBorderLeft(BorderStyle.THIN);
style.setBorderRight(BorderStyle.THIN);
style.setBorderTop(BorderStyle.THIN);
cell.setCellStyle(style); // 将单元格格式赋值给单元格

7)Font类 和 HSSFFont类

Font font = wb.createFont(); // 创建字体格式对象
font.setFontName("宋体"); // 设置字体样式
font.setFontHeightInPoints((short) 11); // 字体大小
font.setBold(boolean bold); // 设置是否粗体
font.setItalic(boolean italic);  // 设置倾斜
font.setUnderline(byte underline); 设置下划线
style.setFont(font); // 将字体赋值给单元格样式(必须将字体样式赋值给单元格样式,再将单元格样式赋值给单元格对象才能生效)

二. Java 使用POI操作Excel

我写项目时将操作Excel的方法进行简单的封装,一下代码是从多个项目中提取的的通用方法,有些是项目中的需求逻辑,相信大家应该能看的出来,大家有什么错误或者补充的可以留言或私信。废话不多说直接上代码:

 /**
     * 搜索所有的excel,并且循环调用excel数据处理方法
     *
     * @throws IOException
     */
    public void readFile() {
        File file = new File(path);
        // 获取包下所有excel文件的名称集合
        String[] filelist = file.list();
        for (int i = 0; i < filelist.length; i++) {
            // 获取excel文件
            readExcelToObj(path + "\\" + filelist[i]);

        }
    }

public List> readExcelToObj(String filepath) {
        HSSFWorkbook wbook = new HSSFWorkbook(new FileInputStream(path));
        Workbook wb = null;
        try {
            wb = WorkbookFactory.create(new File(filepath));
            merge = readExcel(wb, 0, 4, 0);
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return merge;
    }

 /**
     * 读取excel文件
     *
     * @param wb
     * @param sheetIndex    sheet页下标:从0开始
     * @param startReadLine 开始读取的行:从0开始
     * @param tailLine      去除最后读取的行
     */
    private List> readExcel(Workbook wb, int sheetIndex, int startReadLine, int tailLine) {
        Sheet sheet = wb.getSheetAt(sheetIndex);
        Sheet sheets =  wb.createSheet();
        Row row = null;
        int MaxRowNum = sheet.getLastRowNum();
        List> result = new ArrayList<>();
        for (int i = startReadLine; i < MaxRowNum - tailLine + 1; i++) {
            row = sheet.getRow(i);
            List rowContent = new ArrayList<>();
            for (Cell c : row) {
                if (getCellValue(c).contains("备注:1")) {
                    MaxRowNum = c.getRowIndex();
                    c.getColumnIndex();
                    break;
                }
                rowContent.add(getCellValue(c));
            }
            if (!rowContent.isEmpty()) {
                result.add(rowContent);
            }
        }
        return result;
    }

 /**
     * 读取excel文件存储为Map
     *
     * @param wb
     * @param sheetIndex    sheet页下标:从0开始
     * @param startReadLine 开始读取的行:从0开始
     * @param tailLine      去除最后读取的行
     */
    private Map readExcelForMap(Workbook wb, int sheetIndex, int startReadLine, int tailLine,int flat) {
        Sheet sheet = wb.getSheetAt(sheetIndex);
        Row row = null;
        int MaxRowNum = sheet.getLastRowNum();
        Map map = new HashMap<>();
        if(flat == 0||flat== 1){
            for (int i = startReadLine; i < MaxRowNum - tailLine + 1; i++) {
                row = sheet.getRow(i);
                if (getCellValue(row.getCell(0)).contains("备注:1.")) {
                    break;
                }
                String key = getCellValue(row.getCell(1)) + "/" + getCellValue(row.getCell(2)) + "/" + getCellValue(row.getCell(3)) + "/" + getCellValue(row.getCell(4));
                String value = getCellValue(row.getCell(10));

                map.put(key, value);
            }
        }else{
            for (int i = startReadLine; i < MaxRowNum - tailLine + 1; i++) {
                row = sheet.getRow(i);
                String key = getCellValue(row.getCell(4))+"/"+getCellValue(row.getCell(8));
                String value = getCellValue(row.getCell(17));
                map.put(key, value);
            }
        }
        System.out.println(map);
        return map;
    }

 /**
     * 读取excel文件存储为List>
     *
     * @param wb
     * @param sheetIndex    sheet页下标:从0开始
     * @param startReadLine 开始读取的行:从0开始s
     * @param tailLine      去除最后读取的行
     */
    private List> readExcel(Workbook wb, int sheetIndex, int startReadLine, int tailLine, int flat) {
        Sheet sheet = wb.getSheetAt(sheetIndex);
        Row row = null;
        int MaxRowNum = sheet.getLastRowNum();
        List> result = new ArrayList<>();
        for (int i = startReadLine; i < MaxRowNum - tailLine + 1; i++) {
            row = sheet.getRow(i);
            if (getCellValue(row.getCell(1)) == "" && getCellValue(row.getCell(2)) == "" && getCellValue(row.getCell(3)) == "") {
                continue;
            }
            List rowContent = new ArrayList<>();
            if (flat == 3 && i == 3) {
                rowContent.add("序号");
            } else if (flat == 3 && i > 3) {
                rowContent.add(i - 3 + "");
            } else if (flat == 4 && i == 0) {
                rowContent.add("序号");
            } else if (flat == 4 && i > 0) {
                rowContent.add(i + "");
            }
            for (Cell hssfCell : row) {
                if (flat == 1) {
                    if (hssfCell.getColumnIndex() < 9) {
                        rowContent.add(getCellValue(hssfCell));
                    }
                } else if (flat == 2) {
                    if (hssfCell.getColumnIndex() == 3 || hssfCell.getColumnIndex() == 5 || hssfCell.getColumnIndex() == 9 || hssfCell.getColumnIndex() == 11) {
                        rowContent.add(getCellValue(hssfCell));
                    }
                } else if (flat == 3) {
                    rowContent.add(getCellValue(hssfCell));
                } else {

                    rowContent.add(getCellValue(hssfCell));
                }
            }
            result.add(rowContent);
        }
        return result;
    }


/**
     * 找到需要插入的行数,并新建一个POI的row对象
     *
     * @param sheet
     * @param rowIndex
     * @return
     */
    private HSSFRow createRow(HSSFSheet sheet,Integer rowIndex,int n) {
        HSSFRow row = null;
        if (sheet.getRow(rowIndex) != null) {
            int lastRowNo = sheet.getLastRowNum();
            sheet.shiftRows(rowIndex, lastRowNo, n);
        }
        row = sheet.createRow(rowIndex);
        return row;
    }

/**
     * 保存工作薄
     *
     * @param wb
     */
    private void saveExcel(HSSFWorkbook wb,String fileToBeRead) {
        FileOutputStream fileOut;
        try {
            fileOut = new FileOutputStream(fileToBeRead);
            wb.write(fileOut);
            fileOut.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 /**
     * 获取单元格的值
     *
     * @param cell
     * @return
     */
    public String getCellValue(Cell cell) {
        if (cell == null) return "";
        if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
            return cell.getStringCellValue();
        } else if (cell.getCellType() == Cell.CELL_TYPE_BOOLEAN) {
            return String.valueOf(cell.getBooleanCellValue());
        } else if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
            return cell.getCellFormula();
        } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
            return String.valueOf((int) cell.getNumericCellValue());
        }
        return "";
    }

/**
     * 判断指定的单元格是否是合并单元格
     *
     * @param sheet
     * @param row    行下标
     * @param column 列下标
     * @return
     */
    private boolean isMergedRegion(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress range = sheet.getMergedRegion(i);
            int firstColumn = range.getFirstColumn();
            int lastColumn = range.getLastColumn();
            int firstRow = range.getFirstRow();
            int lastRow = range.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    return true;
                }
            }
        }
        return false;
    }

/**
     * 获取合并单元格的值
     *
     * @param sheet
     * @param row
     * @param column
     * @return
     */
    public String getMergedRegionValue(Sheet sheet, int row, int column) {
        int sheetMergeCount = sheet.getNumMergedRegions();
        for (int i = 0; i < sheetMergeCount; i++) {
            CellRangeAddress ca = sheet.getMergedRegion(i);
            int firstColumn = ca.getFirstColumn();
            int lastColumn = ca.getLastColumn();
            int firstRow = ca.getFirstRow();
            int lastRow = ca.getLastRow();
            if (row >= firstRow && row <= lastRow) {
                if (column >= firstColumn && column <= lastColumn) {
                    Row fRow = sheet.getRow(firstRow);
                    Cell fCell = fRow.getCell(firstColumn);
                    return getCellValue(fCell);
                }
            }
        }
        return null;
    }

 /**
     * 设置字体样式
     *
     * @param heigth
     * @param font
     * @param style
     * @param cell
     */
    public void setFontStyle(int heigth, HSSFFont font, HSSFCellStyle style, HSSFCell cell) {
        font.setFontName("宋体");
        font.setFontHeightInPoints((short) heigth);
        style.setFont(font);
        cell.setCellStyle(style);
    }

    public static void setHeadStyle(CellStyle style, HSSFCell cell) {
        style.setWrapText(true);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        cell.setCellStyle(style);
    }

 /**
     * 复制一个单元格样式到目的单元格样式
     * @param fromStyle
     * @param toStyle
     */
    public static void copyCellStyle(HSSFCellStyle fromStyle,
                                     HSSFCellStyle toStyle) {
        toStyle.setAlignment(fromStyle.getAlignmentEnum());
        //边框和边框颜色
        toStyle.setBorderBottom(fromStyle.getBorderBottomEnum());
        toStyle.setBorderLeft(fromStyle.getBorderLeftEnum());
        toStyle.setBorderRight(fromStyle.getBorderRightEnum());
        toStyle.setBorderTop(fromStyle.getBorderTopEnum());
        toStyle.setTopBorderColor(fromStyle.getTopBorderColor());
        toStyle.setBottomBorderColor(fromStyle.getBottomBorderColor());
        toStyle.setRightBorderColor(fromStyle.getRightBorderColor());
        toStyle.setLeftBorderColor(fromStyle.getLeftBorderColor());
        toStyle.setDataFormat(fromStyle.getDataFormat());
        toStyle.setFillPattern(fromStyle.getFillPatternEnum());
//		toStyle.setFont(fromStyle.getFont(null));
        toStyle.setHidden(fromStyle.getHidden());
        toStyle.setIndention(fromStyle.getIndention());//首行缩进
        toStyle.setLocked(fromStyle.getLocked());
        toStyle.setRotation(fromStyle.getRotation());//旋转
        toStyle.setVerticalAlignment(fromStyle.getVerticalAlignmentEnum());
        toStyle.setWrapText(fromStyle.getWrapText());
    }

三. 结语

这是我毕业刚入职第一天的第一个任务,在完全没学过,甚至没听过的情况下,能将功能一个一个实现出来,感觉还是挺有帮助的,希望以后能继续保持学习进步的精神。毕竟有句话说的好,真正的大师永远保持一颗学徒(学秃)的心,我离大师还很远很远,但是我会朝着这个方向一直走下去。

poi