最近寫一個程序,須要操做excel,遂稍微深刻了解下poi從操做,java
在須要複製一個sheet的時候,找到三份資料apache
若是在copy一個cell的時候,須要把樣式也copy過去,怎麼辦,會怎樣呢?app
若是像第三份資料中所作,會建立太多的style,而這些style又是重複的 ,毫無心義,數據多了還報錯xss
若是像第二份資料中所作,前提是同一個workbook,也不存在copy style 的問題,只不過是不一樣的cell引用相同的style而已測試
若是像第一份資料所作,他本身都註釋掉了,由於報錯this
暫時沒測試過,寫出來就火燒眉毛要分享了。.net
import org.apache.poi.ss.usermodel.CellStyle; import org.apache.poi.ss.usermodel.Workbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 提供經常使用excel操做<br> * <ul> * <li></li> * </ul> */ public class ExcelOperationUtil { private static Logger logger = LoggerFactory.getLogger(ExcelOperationUtil.class); /** * 把一個excel中的styleTable複製到另外一個excel中 * @return StyleMapping 兩個文件中styleTable的映射關係 * @see StyleMapping */ public static StyleMapping copyCellStyle(Workbook srcBook, Workbook desBook){ if (null == srcBook || null == desBook) { throw new ExcelExecption("源excel 或 目標excel 不存在"); } if (srcBook.equals(desBook)) { throw new ExcelExecption("不要使用此方法在同一個文件中copy style"); } logger.debug("src中style number:{}, des中style number:{}", srcBook.getNumCellStyles(), desBook.getNumCellStyles()); short[] src2des = new short[srcBook.getNumCellStyles()]; short[] des2src = new short[desBook.getNumCellStyles() + srcBook.getNumCellStyles()]; for(short i=0;i<srcBook.getNumCellStyles();i++){ //創建雙向映射 CellStyle srcStyle = srcBook.getCellStyleAt(i); CellStyle desStyle = desBook.createCellStyle(); src2des[srcStyle.getIndex()] = desStyle.getIndex(); des2src[desStyle.getIndex()] = srcStyle.getIndex(); //複製樣式 desStyle.cloneStyleFrom(srcStyle); } return new StyleMapping(des2src, src2des); } /** * 存放兩個excel文件中的styleTable的映射關係,以便於在複製表格時,在目標文件中獲取到對應的樣式 */ public static class StyleMapping { /** * */ private short[] des2srcIndexMapping; /** * */ private short[] src2desIndexMapping; /** * 不容許其餘類建立此類型對象 */ private StyleMapping() { } private StyleMapping(short[] des2srcIndexMapping, short[] src2desIndexMapping) { this.des2srcIndexMapping = des2srcIndexMapping; this.src2desIndexMapping = src2desIndexMapping; } public short srcIndex(short desIndex) { if (desIndex < 0 || desIndex >= this.des2srcIndexMapping.length) { throw new ExcelExecption("索引越界:源文件styleNum=" + this.des2srcIndexMapping.length + " 訪問位置=" + desIndex); } return this.des2srcIndexMapping[desIndex]; } /** * 根據源文件的style的index,獲取目標文件的style的index * @param srcIndex 源excel中style的index * @return desIndex 目標excel中style的index */ public short desIndex(short srcIndex) { if (srcIndex < 0 || srcIndex >= this.src2desIndexMapping.length) { throw new ExcelExecption("索引越界:源文件styleNum=" + this.src2desIndexMapping.length + " 訪問位置=" + srcIndex); } return this.src2desIndexMapping[srcIndex]; } } }
工做忙了幾天,終於能夠回頭把這件事結束掉了debug
<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.17</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-scratchpad</artifactId> <version>3.17</version> </dependency>
爲啥貼出依賴?由於我一開始用3.8版本,若是是xls就能夠,若是是xlsx死活不行,最後,換掉版本就能夠了。excel
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.*; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Iterator; /** * 提供經常使用excel操做<br> * <ul> * <li></li> * </ul> */ public class ExcelOperationUtil { private static Logger logger = LoggerFactory.getLogger(ExcelOperationUtil.class); /** * sheet 複製,複製數據、若是同一個文件,複製樣式,不一樣文件則只複製數據<br/> * 若是是同book中複製,建議使用workbook中的cloneSheet()方法<br/> * * <br/>建議用於 不一樣book間只複製數據 * */ public static void copySheet(Sheet srcSheet, Sheet desSheet) { copySheet(srcSheet, desSheet, true, true, null); } /** * sheet 複製,若是同一個文件,複製樣式,不一樣文件則不復制<br/> * * <br/>建議用於 同book中,只複製樣式,不復制數據<br/> * eg: copySheet(srcSheet, desSheet, false) * * @param copyValueFlag 控制是否複製數據 */ public static void copySheet(Sheet srcSheet, Sheet desSheet, boolean copyValueFlag) { copySheet(srcSheet, desSheet, copyValueFlag, true, null); } /** * sheet 複製,複製數據、樣式<br/> * * <br/>建議用於 不一樣book間複製,同時複製數據和樣式<br/> * eg: copySheet(srcSheet, desSheet, mapping) * * @param mapping 不一樣文件間複製時,若是要複製樣式,必傳,不然不復制樣式 */ public static void copySheet(Sheet srcSheet, Sheet desSheet, StyleMapping mapping) { copySheet(srcSheet, desSheet, true, true, mapping); } /** * sheet 複製,複製數據<br/> * * <br/>建議用於 同book中,只複製數據,不復制樣式<br/> * eg: copySheet(srcSheet, desSheet, false, null) * * @param srcSheet * @param desSheet * @param copyStyleFlag * @param mapping */ public static void copySheet(Sheet srcSheet, Sheet desSheet, boolean copyStyleFlag, StyleMapping mapping) { copySheet(srcSheet, desSheet, true, copyStyleFlag, mapping); } /** * sheet 複製, 靈活控制是否控制數據、樣式<br/> * * <br/>不建議直接使用 * * @param copyValueFlag 控制是否複製數據 * @param copyStyleFlag 控制是否複製樣式 * @param mapping 不一樣book中複製樣式時,必傳 */ public static void copySheet(Sheet srcSheet, Sheet desSheet, boolean copyValueFlag, boolean copyStyleFlag, StyleMapping mapping) { if (srcSheet.getWorkbook() == desSheet.getWorkbook()) { logger.warn("統一workbook內複製sheet建議使用 workbook的cloneSheet方法"); } //合併區域處理 copyMergedRegion(srcSheet, desSheet); //行復制 Iterator<Row> rowIterator = srcSheet.rowIterator(); int areadlyColunm = 0; while (rowIterator.hasNext()) { Row srcRow = rowIterator.next(); Row desRow = desSheet.createRow(srcRow.getRowNum()); copyRow(srcRow, desRow, copyValueFlag, copyStyleFlag, mapping); //調整列寬(增量調整) if (srcRow.getPhysicalNumberOfCells() > areadlyColunm) { for (int i = areadlyColunm; i < srcRow.getPhysicalNumberOfCells(); i++) { desSheet.setColumnWidth(i, srcSheet.getColumnWidth(i)); } areadlyColunm = srcRow.getPhysicalNumberOfCells(); } } } /** * 複製行 */ public static void copyRow(Row srcRow, Row desRow) { copyRow(srcRow, desRow, true, true, null); } /** * 複製行 */ public static void copyRow(Row srcRow, Row desRow, boolean copyValueFlag) { copyRow(srcRow, desRow, copyValueFlag, true, null); } /** * 複製行 */ public static void copyRow(Row srcRow, Row desRow, StyleMapping mapping) { copyRow(srcRow, desRow, true, true, mapping); } /** * 複製行 */ public static void copyRow(Row srcRow, Row desRow, boolean copyStyleFlag, StyleMapping mapping) { copyRow(srcRow, desRow, true, copyStyleFlag, mapping); } /** * 複製行 */ public static void copyRow(Row srcRow, Row desRow,boolean copyValueFlag, boolean copyStyleFlag, StyleMapping mapping) { Iterator<Cell> it = srcRow.cellIterator(); while (it.hasNext()) { Cell srcCell = it.next(); Cell desCell = desRow.createCell(srcCell.getColumnIndex()); copyCell(srcCell, desCell, copyValueFlag, copyStyleFlag, mapping); } } /** * 複製區域(合併單元格) */ public static void copyMergedRegion(Sheet srcSheet, Sheet desSheet) { int sheetMergerCount = srcSheet.getNumMergedRegions(); for (int i = 0; i < sheetMergerCount; i++) { desSheet.addMergedRegion(srcSheet.getMergedRegion(i)); CellRangeAddress cellRangeAddress = srcSheet.getMergedRegion(i); } } /** * 複製單元格,複製數據,若是同文件,複製樣式,不一樣文件則不復制樣式 */ public static void copyCell(Cell srcCell, Cell desCell) { copyCell(srcCell, desCell, true, true,null); } /** * 複製單元格, 若是同文件,複製樣式,不一樣文件則不復制樣式 * @param copyValueFlag 控制是否複製數據 */ public static void copyCell(Cell srcCell, Cell desCell, boolean copyValueFlag) { copyCell(srcCell, desCell, copyValueFlag, true, null); } /** * 複製單元格,複製數據,複製樣式 * @param mapping 不一樣文件間複製時,若是要複製樣式,必傳,不然不復制樣式 */ public static void copyCell(Cell srcCell, Cell desCell, StyleMapping mapping) { copyCell(srcCell, desCell, true, true, mapping); } /** * 複製單元格,複製數據 * @param copyStyleFlag 控制是否複製樣式 * @param mapping 不一樣文件間複製時,若是要複製樣式,必傳,不然不復制樣式 */ public static void copyCell(Cell srcCell, Cell desCell, boolean copyStyleFlag, StyleMapping mapping) { copyCell(srcCell, desCell, true, copyStyleFlag, mapping); } /** * 複製單元格 * @param copyValueFlag 控制是否複製單元格的內容 * @param copyStyleFlag 控制是否複製樣式 * @param mapping 不一樣文件間複製時,若是須要連帶樣式複製,必傳,不然不復制樣式 */ public static void copyCell(Cell srcCell, Cell desCell, boolean copyValueFlag, boolean copyStyleFlag, StyleMapping mapping) { Workbook srcBook = srcCell.getSheet().getWorkbook(); Workbook desBook = desCell.getSheet().getWorkbook(); //複製樣式 //若是是同一個excel文件內,連帶樣式一塊兒複製 if (srcBook == desBook && copyStyleFlag) { //同文件,複製引用 desCell.setCellStyle(srcCell.getCellStyle()); } else if (copyStyleFlag) { //不一樣文件,經過映射關係複製 if (null != mapping) { short desIndex = mapping.desIndex(srcCell.getCellStyle().getIndex()); desCell.setCellStyle(desBook.getCellStyleAt(desIndex)); } } //複製評論 if (srcCell.getCellComment() != null) { desCell.setCellComment(srcCell.getCellComment()); } //複製內容 desCell.setCellType(srcCell.getCellTypeEnum()); if (copyValueFlag) { switch (srcCell.getCellTypeEnum()) { case STRING: desCell.setCellValue(srcCell.getStringCellValue()); break; case NUMERIC: desCell.setCellValue(srcCell.getNumericCellValue()); break; case FORMULA: desCell.setCellFormula(srcCell.getCellFormula()); break; case BOOLEAN: desCell.setCellValue(srcCell.getBooleanCellValue()); break; case ERROR: desCell.setCellValue(srcCell.getErrorCellValue()); break; case BLANK: //nothing to do break; default: break; } } } /** * 把一個excel中的styleTable複製到另外一個excel中<br> * 若是是同一個excel文件,就不用複製styleTable了 * @return StyleMapping 兩個文件中styleTable的映射關係 * @see StyleMapping */ public static StyleMapping copyCellStyle(Workbook srcBook, Workbook desBook){ if (null == srcBook || null == desBook) { throw new ExcelException("源excel 或 目標excel 不存在"); } if (srcBook.equals(desBook)) { throw new ExcelException("不要使用此方法在同一個文件中copy style,同一個excel中複製sheet不須要copy Style"); } if ((srcBook instanceof HSSFWorkbook && desBook instanceof XSSFWorkbook) || (srcBook instanceof XSSFWorkbook && desBook instanceof HSSFWorkbook)) { throw new ExcelException("不支持在不一樣的版本的excel中複製樣式)"); } logger.debug("src中style number:{}, des中style number:{}", srcBook.getNumCellStyles(), desBook.getNumCellStyles()); short[] src2des = new short[srcBook.getNumCellStyles()]; short[] des2src = new short[desBook.getNumCellStyles() + srcBook.getNumCellStyles()]; for(short i=0;i<srcBook.getNumCellStyles();i++){ //創建雙向映射 CellStyle srcStyle = srcBook.getCellStyleAt(i); CellStyle desStyle = desBook.createCellStyle(); src2des[srcStyle.getIndex()] = desStyle.getIndex(); des2src[desStyle.getIndex()] = srcStyle.getIndex(); //複製樣式 desStyle.cloneStyleFrom(srcStyle); } return new StyleMapping(des2src, src2des); } /** * 存放兩個excel文件中的styleTable的映射關係,以便於在複製表格時,在目標文件中獲取到對應的樣式 */ public static class StyleMapping { /** * */ private short[] des2srcIndexMapping; /** * */ private short[] src2desIndexMapping; /** * 不容許其餘類建立此類型對象 */ private StyleMapping() { } public StyleMapping(short[] des2srcIndexMapping, short[] src2desIndexMapping) { this.des2srcIndexMapping = des2srcIndexMapping; this.src2desIndexMapping = src2desIndexMapping; } public short srcIndex(short desIndex) { if (desIndex < 0 || desIndex >= this.des2srcIndexMapping.length) { throw new ExcelException("索引越界:源文件styleNum=" + this.des2srcIndexMapping.length + " 訪問位置=" + desIndex); } return this.des2srcIndexMapping[desIndex]; } /** * 根據源文件的style的index,獲取目標文件的style的index * @param srcIndex 源excel中style的index * @return desIndex 目標excel中style的index */ public short desIndex(short srcIndex) { if (srcIndex < 0 || srcIndex >= this.src2desIndexMapping.length) { throw new ExcelException("索引越界:源文件styleNum=" + this.src2desIndexMapping.length + " 訪問位置=" + srcIndex); } return this.src2desIndexMapping[srcIndex]; } } }
一個自定義異常類code
public class ExcelException extends RuntimeException { public ExcelException() { } public ExcelException(String message) { super(message); } public ExcelException(String message, Throwable cause) { super(message, cause); } public ExcelException(Throwable cause) { super(cause); } public ExcelException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); } }