一:Java POI 基本簡介
Apache POI(Poor Obfuscation Implementation)是用Java編寫的免費開源的跨平台的Java API,Apache POI提供API給Java程序對Microsoft Office格式檔案讀和寫的功能,其中使用最多的就是使用POI操作Excel文件
它是創建和維護操作各種符合Office Open XML(OOXML)標准和微軟的OLE 2復合文檔格式(OLE2)的Java API。用它可以使用Java讀取和創建,修改MS Excel文件.而且,還可以使用Java讀取和創建MS Word和MSPowerPoint文件。Apache POI 提供Java操作Excel解決方案(適用於Excel97-2008)
POI發行版可以對許多文檔文件格式的支持。這種支持是在幾個JAR文件中提供的。並不是每種格式都需要所有的JAR。下面我介紹一下POI組件、Maven存儲庫標記和項目的Jar文件之間的關系 【 詳細POI API 】
組件 操作格式 依賴 說明 XSSF Excel XLSX poi-ooxml XSLF PowerPoint PPTX poi-ooxml XWPF Word DOCX poi-ooxml XDGF Visio VSDX poi-ooxml POIFS OLE2 Filesystem poi 需要處理基於OLE2/POIFS的文件 HPSF OLE2 Property Sets poi HSSF Excel XLS poi 僅支持HSSF(只可以操作XLS) DDF Escher common drawings poi HSLF PowerPoint PPT poi-scratchpad HWPF Word DOC poi-scratchpad HDGF Visio VSD poi-scratchpad HPBF Publisher PUB poi-scratchpad HSMF Outlook MSG poi-scratchpad HWMF WMF drawings poi-scratchpad 特殊: Common SL: PPT和PPTX poi-scratchpad 和 poi-ooxml SL代碼在核心POIjar中,但是實現的是poi-scratchpad和poi-ooxml Common SS: XLS和XLSX poi-ooxml WorkbookFactory和其它實現都需要poi-ooxml,而不僅僅是核心po OpenXML4J: OOXML poi-ooxml和poi-ooxml-lite或poi-ooxml-full
maven關於POI操作的整套依賴:

<!--設置maven使用什么版本的jdk解析編譯 注意4.1.2版本的jdk編譯要是1.8及以上 --> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.9</maven.compiler.source> <maven.compiler.target>1.9</maven.compiler.target> </properties> <dependencies> <!--前3個坐標按照上表搭配--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>4.1.2</version> </dependency> <!--poi其它依賴包,正常使用可以不用添加--> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-examples</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-excelant</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml-schemas</artifactId> <version>4.1.2</version> </dependency> </dependencies>
二:POI操作之XSSF(基本)
XSSF是我們最常用的api了,它可以操作我們最常用的Excel XLSX表格,而Excel XLS老板格式的表格慢慢淡出了我們的視線,因為老版格式的表格只能存在65535行,而XLSX就不會出現這個問題,我針對XSSF詳細介紹
1:簡單創建xlsx之流程了解
操作XLSX文件我們得使用XSSFWorkbook類來構建我們的工作簿,其實查詢繼承關系,這一類的工作簿都繼承自Workbook接口,它實現了HSSFWorkbook,SXSSFWorkbook,XSSFWorkbook等

public static void main(String[] args) throws IOException { //①:創建工作簿 Workbook workbook = new XSSFWorkbook(); //②:創建工作表 打開Xlsx文件最下邊的sheet1、sheet2工作表 Sheet sheet = workbook.createSheet("螞蟻小哥日常統計"); //③:通過下面2行代碼創建一個坐標為0,0 並寫上內容 對應Excel 1,1 位置 //創建行 當前創建的為0行 對應Excel第一行 Row row = sheet.createRow(0); //創建列 當前創建列為0列 對應Excel第一列 Cell cell = row.createCell(0); //寫入內容 今天買菜花300 cell.setCellValue("今天買菜花300"); //或者鏈式調用寫法:sheet.createRow(0).createCell(0).setCellValue("今天買菜花300"); //④:把構建的內存數據寫入到磁盤 確保有這個磁盤 OutputStream out = new FileOutputStream("h://test.xlsx"); workbook.write(out); //⑤:關閉資源 out.close(); workbook.close(); }
2:xlsx文件創建日期類型及不同類型的單元格
對於寫出的數據中包含日期類型的話,我們就得進行樣式轉換其中操作樣式的 CellStyle 接口方法,它內部定義了各種樣式操作,如邊框顏色、對齊方式、字體、顏色等等,但是我要介紹的是樣式里的 setDataFormat 方法,可是它接收的是short參數,這就使得我要介紹 CreationHelper 接口,它里面的createDataFormat方法可以創建DataFormat實例並返回short參數

public static void main(String[] args) throws IOException { //創建工作簿 Workbook workbook = new XSSFWorkbook(); //創建工作表 不指定名則默認Sheet(0~N) Sheet sheet = workbook.createSheet(); //創建第一行 Row row = sheet.createRow(0); //創建第一列 Cell cellA = row.createCell(0); //在0,0的位置寫入日期數據 cellA.setCellValue(new Date()); //返回一個對象,該對象處理XSSF各種實例的具體類的實例化 CreationHelper creationHelper = workbook.getCreationHelper(); //創建新的DataFormat實例。獲取與給定格式字符串匹配的格式索引,在需要時創建一個新的格式條目。 short format = creationHelper.createDataFormat().getFormat("yyyy-MM-dd"); //通過Workbook來獲取一個樣式操作類來對已有的表設置樣式 CellStyle cellStyle = workbook.createCellStyle(); //把日期格式設置當當前樣式cellStyle中 cellStyle.setDataFormat(format); //在1,1位置寫入日期數據 並對1,1位置寫入樣式 Cell cellB = row.createCell(1); cellB.setCellValue(new Date()); cellB.setCellStyle(cellStyle); //把構建的內存數據寫入到磁盤 OutputStream out = new FileOutputStream("h://test1.xlsx"); workbook.write(out); //關閉資源 out.close(); workbook.close(); }

public static void main(String[] args) throws IOException { //創建工作簿 Workbook workbook = new XSSFWorkbook(); //創建工作表 不指定名則默認Sheet(0~N) Sheet sheet = workbook.createSheet(); Row row = sheet.createRow(0); row.createCell(0).setCellValue("我是字符串"); row.createCell(1).setCellValue(25.5555); row.createCell(2).setCellValue(true); //對0,3 0,4 時間類和日歷類 row.createCell(3).setCellValue(new Date()); row.createCell(4).setCellValue(Calendar.getInstance()); //把構建的內存數據寫入到磁盤 OutputStream out = new FileOutputStream("h://test1.xlsx"); workbook.write(out); //關閉資源 out.close(); workbook.close(); }
3:總結上面1~2節知識來個總結
學完基礎的我們就可以自己動手寫個簡單的創建xlsx格式的文件了,再接下來的幾節我將創建更好看的樣式表格及讀xlsx文件

public static void main(String[] args) throws IOException { //創建數據源 Object[] title = {"ID", "姓名", "零花錢", "生日", "是否被刪除"}; Object[] stu1 = {"tx001", "許齡月", 66.66, new Date(), true}; Object[] stu2 = {"tx002", "周星馳", 66.66, new Date(213465654L), false}; List<Object[]> list = new ArrayList<>(); list.add(title); list.add(stu1); list.add(stu2); //創建工作簿 Workbook workbook = new XSSFWorkbook(); //創建工作表 Sheet sheet = workbook.createSheet("總結"); //循環創建 for (int r = 0; r < list.size(); r++) { //創建行 Row row = sheet.createRow(r); for (int c = 0; c < list.get(r).length; c++) { if (r == 0) { //標題寫入 //創建列 Cell cell = row.createCell(c); cell.setCellValue(list.get(r)[c].toString()); } else { Object o = list.get(r)[c]; //獲取每個單元格數據然后匹配類型 //創建列 Cell cell = row.createCell(c); //此時數據是要改變樣式 if (o instanceof Date) { CellStyle cellStyle = workbook.createCellStyle(); cellStyle.setDataFormat(workbook.getCreationHelper().createDataFormat().getFormat("yyyy-mm-dd")); cell.setCellValue((Date) list.get(r)[c]); cell.setCellStyle(cellStyle); } else { //寫入正文 cell.setCellValue(list.get(r)[c].toString()); } } } } //寫出及關閉 OutputStream out = new FileOutputStream("h:\\test02.xlsx"); workbook.write(out); out.close(); workbook.close(); }
4:從xlsx文件中遍歷數據
遍歷數據可謂是重點了,我們得創建一個工作簿並傳入xlsx文件,其中獲取起始行和結尾行則使用 getFirstRowNum 和 getLastRowNum 方法,但是獲取的每個單元格表格數據類型不同則需要使用類型匹配

public static void main(String[] args) throws IOException { //創建工作簿並傳入一個真實存在的文件 Workbook workbook = new XSSFWorkbook("h:\\abc.xlsx"); //獲取文件的第一個工作表 Sheet sheetAt = workbook.getSheetAt(0); //獲取工作表中的起始行 int rowStart = Math.max(0, sheetAt.getFirstRowNum()); //獲取工作表中的結束行,如果大於21行則按照21行讀 0開始-20 int rowEnd = Math.min(20, sheetAt.getLastRowNum()); //循環行rowStart ~ rowEnd for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) { //創建行實例 Row row = sheetAt.getRow(rowNum); //為空則全部結束 if (row == null) { continue; } //不為空則創建每行的列 lastColumn 如果讀到的行數大於11行則按照11行讀取 int lastColumn = Math.min(10, row.getLastCellNum()); //循環每行的列0 ~ lastColumn for (int colNum = 0; colNum < lastColumn; colNum++) { //創建列的實例 Cell cell = row.getCell(colNum); //列為空的話就跳出循環去遍歷下一列 if (cell == null) { continue; } else { //switch來匹配類型 ,因為表格的每個類型不一樣 switch (cell.getCellType()) { case NUMERIC: //數字類型 (這個相對復雜,還要判斷是數字還是日期) //通過查找StylesSource獲取格式字符串的內容 String formatString = cell.getCellStyle().getDataFormatString(); //判斷當前的字符串形式的內容是否以m/d/yy的日期格式 if (formatString.equals("m/d/yy")) { System.out.print(cell.getDateCellValue() + " | "); } else { System.out.print(cell.getNumericCellValue() + " | "); } break; case STRING: //字符串類型 System.out.print(cell.getStringCellValue() + " | "); break; case BOOLEAN: //真假值 System.out.print(cell.getBooleanCellValue() + " | "); break; case ERROR: //錯誤類型 System.out.print(cell.getErrorCellValue() + " | "); break; case BLANK: //空數據 System.out.print("空數據" + " | "); break; case FORMULA: //計算類型 System.out.print(cell.getCellFormula() + " | "); case _NONE: //未知類型 System.out.print("未知類型" + " | "); } } } System.out.println(); } workbook.close(); }
三:POI操作之XSSF(樣式)
1:設置單元格的對齊方式
說到對齊方式我們就得談談2個枚舉類了 HorizontalAlignment(水平對齊)VerticalAlignment(垂直對齊),但是我們設置對齊方式還得借助CellStyle樣式接口內部的實現類完成,通過 setAlignment 和 setVerticalAlignment 方法來對單元格設置對齊方式

public static void main(String[] args) throws IOException { //創建工作簿和創建工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); //設置行 Row row = sheet.createRow(0); //設置行高度 row.setHeightInPoints(60); //創建0,1單元格 Cell cell = row.createCell(1); cell.setCellValue("啦啦"); //創建樣式 CellStyle cellStyle = workbook.createCellStyle(); //設置單元格的水平對齊類型。 此時水平居中 cellStyle.setAlignment(HorizontalAlignment.CENTER); //設置單元格的垂直對齊類型。 此時垂直靠底邊 cellStyle.setVerticalAlignment(VerticalAlignment.BOTTOM); //把樣式設置到單元格上 cell.setCellStyle(cellStyle); //寫出及關閉 OutputStream out = new FileOutputStream("h:\\test03.xlsx"); workbook.write(out); out.close(); workbook.close(); }
2:設置單元格的邊框樣式及邊框的顏色
感覺這個用處並不大,要設置漂亮樣式可以使用一番 主要是通過 CellStyle 來設置邊框和邊框顏色,具體的就得參照BorderStyle、IndexedColors這2個枚舉類來獲取具體的樣式

public static void main(String[] args) throws IOException { //創建工作簿和創建工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); //設置行 Row row = sheet.createRow(1); //為了可以看到樣式 特地設置大高度 row.setHeightInPoints(60); //創建0,1單元格 Cell cell = row.createCell(1); cell.setCellValue("啦"); //創建樣式 CellStyle cellStyle = workbook.createCellStyle(); //通過set設置邊框樣式及邊框顏色 反之通過get可以獲取設置的樣式 cellStyle.setBorderBottom(BorderStyle.DOTTED); cellStyle.setBottomBorderColor(IndexedColors.GREEN.getIndex()); cellStyle.setBorderTop(BorderStyle.THIN); cellStyle.setTopBorderColor(IndexedColors.CORAL.getIndex()); cellStyle.setBorderLeft(BorderStyle.THIN); cellStyle.setLeftBorderColor(IndexedColors.RED.getIndex()); cellStyle.setBorderRight(BorderStyle.DASH_DOT_DOT); cellStyle.setRightBorderColor(IndexedColors.AQUA.getIndex()); //別忘了把剛才這些設置的樣式設置到單元格上 cell.setCellStyle(cellStyle); //寫出及關閉 OutputStream out = new FileOutputStream("h:\\test03.xlsx"); workbook.write(out); out.close(); workbook.close(); }
3:設置單元格填色
有時候我們會對單元格前景/背景進行色彩設置,以及對單元格的填充圖案,這時候我們就會用到樣式類里面的填充方法,具體看代碼

public static void main(String[] args) throws IOException { //創建工作簿和創建Sheet0工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); //設置第一列的寬度是20個字符寬度 sheet.setColumnWidth(1, 20*256); //創建第一行 Row row = sheet.createRow(1); row.setHeightInPoints(60); //創建樣式對象 CellStyle style = workbook.createCellStyle(); //設置背景色 style.setFillBackgroundColor(IndexedColors.AQUA.getIndex()); //設置填充圖案(紋理)填充圖案默認為黑色 style.setFillPattern(FillPatternType.BIG_SPOTS); //此時我設置填充圖案(前景色為紅色) style.setFillForegroundColor(IndexedColors.RED.getIndex()); //創建行(1,1)並設置文本加樣式 Cell cell = row.createCell(1); cell.setCellValue("螞蟻小哥"); cell.setCellStyle(style); //創建流並寫出文件關閉流 OutputStream out = new FileOutputStream("h:\\test3.xlsx"); workbook.write(out); out.close(); workbook.close(); }

<!--Enum FillPatternType:--> <!--Enum:IndexedColors:--> 常量名 漢譯 常量名 漢譯 常量名 漢譯 常量名 漢譯 ALT_BARS: 寬點 BLACK: 黑色 GREEN: 綠色 DARK_RED:深紅色 BIG_SPOTS: 大斑點 BLACK1: 黑色1 VIOLET: 紫羅蘭 DARK_BLUE: 深藍色 BRICKS: 磚狀布局 WHITE: 白色 TEAL: 藍綠色 DARK_YELLOW:深黃色 DIAMONDS: 鑽石 WHITE1: 白色1 MAROON: 栗色 DARK_GREEN: 深綠色 FINE_DOTS: 小細點 RED: 紅色 ROSE: 粉紅色 DARK_TEAL: 深青色 LEAST_DOTS: 最小點 RED1: 紅色1 AQUA: 水綠色 LIGHT_GREEN: 淺綠色 LESS_DOTS: 少點 BRIGHT_GREEN:亮綠色 LIME: 石灰色 LIGHT_YELLOW: 淺黃色 NO_FILL: 無背景 BRIGHT_GREEN1:亮綠色1 GOLD: 金 LIGHT_ORANGE:淡橙色 SOLID_FOREGROUND: 實填 BLUE: 藍色 LAVENDER:淡紫色 LIGHT_BLUE: 淺藍色 SPARSE_DOTS: 稀疏點 BLUE1: 藍色1 BROWN: 棕色 LIGHT_CORNFLOWER_BLUE:淺矢車菊藍 SQUARES: 正方形 YELLOW: 黃色 PLUM: 紫紅色 PALE_BLUE: 淡藍色 THICK_BACKWARD_DIAG:厚厚的后向對角線 YELLOW1: 黃色1 INDIGO: 靛藍色 SEA_GREEN: 海綠色 THICK_FORWARD_DIAG: 厚正面對角線 PINK: 粉紅 TAN: 棕黃色 BLUE_GREY: 藍灰 THICK_HORZ_BANDS: 厚水平帶 PINK1: 粉色1 ORCHID: 蘭花色 SKY_BLUE: 天空藍色 THICK_VERT_BANDS: 厚垂直帶 TURQUOISE: 青綠色 CORAL: 珊瑚色 GREY_25_PERCENT:灰25% THIN_BACKWARD_DIAG: 薄后向對角線 TURQUOISE1: 青綠色1 ROYAL_BLUE:皇家藍 GREY_40_PERCENT:灰40% THIN_FORWARD_DIAG: 細正對角線 LEMON_CHIFFON: 檸檬雪紡 ORNFLOWER_BLUE:矢車菊藍 GREY_50_PERCENT:灰50% THIN_HORZ_BANDS: 薄水平帶 LIGHT_TURQUOISE:淺青綠色 ORANGE: 桔黃色的 GREY_80_PERCENT:灰80% THIN_VERT_BANDS: 薄垂直帶 LIGHT_TURQUOISE1:淺青綠色1 OLIVE_GREEN: 橄欖綠 AUTOMATIC:自然色
4:合並單元格
有時候我們要設置單元格的合並,這個時候我們就可以使用addMergedRegion方法完成

public static void main(String[] args) throws IOException { //創建工作簿和創建Sheet0工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); //設置單元格合並 0開始索引 //前2個參數設置開始行到結束行 //后2個參數設置開始列到結束列 切記這和我們坐標軸不一樣 sheet.addMergedRegion(new CellRangeAddress(1,1,1,5)); //創建行 Row row = sheet.createRow(1); //創建列此時為1,1 並為單元格設置信息 Cell cell = row.createCell(1); cell.setCellValue("螞蟻小哥"); //創建流並寫出文件關閉流 OutputStream out = new FileOutputStream("h:\\test3.xlsx"); workbook.write(out); out.close(); workbook.close(); }
5:字體樣式設置
對字體的設置我們得通過工作簿先創建字體樣式類,然后再進行字體的設置

public static void main(String[] args) throws IOException { //創建工作簿和創建Sheet0工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet(); //創建行 Row row = sheet.createRow(1); //創建字體類 Font font = workbook.createFont(); //設置字體顏色 font.setColor(IndexedColors.RED1.getIndex()); //設置字體 true粗體(默認) false細 font.setBold(false); //設置字體大小 font.setFontHeightInPoints((short) 60); //設置字體名 如楷體,微軟雅黑....中文和英文表示都行 font.setFontName("楷體"); //傾斜設置 font.setItalic(true); //設置刪除線 font.setStrikeout(true); //創建樣式類 CellStyle cellStyle = workbook.createCellStyle(); //樣式設置font樣式 cellStyle.setFont(font); //創建列此時為1,1 並為單元格設置信息 Cell cell = row.createCell(1); cell.setCellValue("螞蟻小哥"); cell.setCellStyle(cellStyle); //創建流並寫出文件關閉流 OutputStream out = new FileOutputStream("h:\\test3.xlsx"); workbook.write(out); out.close(); workbook.close(); }
6:使用函數方便構建樣式及單元格合並
通過上面的樣式創建和單元格的創建我們發現,每次設置樣式都要創建對象,麻煩,還浪費內存,其實ReginUtil(區域工具)CellUtil(樣式工具)可以很快構建我們的樣式,可以簡寫很多代碼

public static void main(String[] args) throws IOException { //創建工作簿和創建Sheet0工作表 Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("new sheet"); //創建2行 對應表中的第1行和第2行 0開始 Row row = sheet.createRow(1); Row row2 = sheet.createRow(2); //創建1,1的單元格 Cell cell = row.createCell(1); cell.setCellValue("螞蟻小哥"); //此類可以創建單元格的范圍 B2(1,1):E5(4,4) CellRangeAddress region = CellRangeAddress.valueOf("B2:E5"); //傳遞給合並單元格方法里 sheet.addMergedRegion(region); //設置四邊樣式及顏色 但是得傳遞Sheet和CellRangeAddress RegionUtil.setBorderBottom(BorderStyle.MEDIUM_DASHED, region, sheet); RegionUtil.setBorderTop(BorderStyle.MEDIUM_DASHED, region, sheet); RegionUtil.setBorderLeft(BorderStyle.MEDIUM_DASH_DOT, region, sheet); RegionUtil.setBorderRight(BorderStyle.MEDIUM_DASHED, region, sheet); RegionUtil.setBottomBorderColor(IndexedColors.BLUE.getIndex(), region, sheet); RegionUtil.setTopBorderColor(IndexedColors.AQUA.getIndex(), region, sheet); RegionUtil.setLeftBorderColor(IndexedColors.RED.getIndex(), region, sheet); RegionUtil.setRightBorderColor(IndexedColors.AQUA.getIndex(), region, sheet); //創建樣式類 CellStyle style = workbook.createCellStyle(); //設置空格數以縮進單元格中的文本 style.setIndention((short) 4); CellUtil.createCell(row, 8, "my name is ant", style); Cell cell2 = CellUtil.createCell(row2, 8, "阿三大蘇打"); //設置居中 CellUtil.setAlignment(cell2, HorizontalAlignment.CENTER); //創建流並寫出文件關閉流 OutputStream out = new FileOutputStream("h:\\test3.xlsx"); workbook.write(out); out.close(); workbook.close(); }
.