package com.deloitte.tms.eit.neweit.utils; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; import java.util.List; import org.apache.poi.ss.util.CellRangeAddress; import org.apache.poi.xssf.usermodel.XSSFCell; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCell; import com.deloitte.tms.base.srv.util.StringUtil; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.FormulaEvaluator; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; public class ReadMergeRegionExcel { /** * 讀取excel文件 * @param * @param sheetIndex sheet頁下標:從0開始 * @param startReadLine 開始讀取的行:從0開始 * @param tailLine 去除最后讀取的行 */ public static void readExcelSheet( Sheet sheet, int startReadLine) { Row row = null; for(int i=startReadLine; i<=sheet.getLastRowNum(); i++) { row = sheet.getRow(i); for(Cell c : row) { c.setCellType(Cell.CELL_TYPE_STRING); boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex()); //判斷是否具有合並單元格 if(isMerge) { /* String rs = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex()); System.out.print(rs + " "); */ }else { System.out.print(c.getRichStringCellValue()+" "); } } System.out.println(); } } /** * 獲取合並單元格的值 * @param sheet * @param row * @param column * @return */ public static String getMergedRegionValue(Sheet sheet ,int row , int column,FormulaEvaluator eva){ 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,(FormulaEvaluator)eva) ; } } } return null ; } /** * 獲取單元格的值 * @param cell * @return */ public static 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(cell.getNumericCellValue()); } return ""; } public static String getCellValue(Cell cell, FormulaEvaluator eva) { if (cell == null) { return ""; } else { switch (cell.getCellType()) { case 0: boolean b1 = HSSFDateUtil.isCellDateFormatted(cell); if (b1) { Date date = cell.getDateCellValue(); SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return df.format(date); } cell.setCellType(1); return cell.getStringCellValue(); case 1: return cell.getStringCellValue(); case 2: if (eva == null) { return cell.getCellFormula(); } else { // String cellFormula = cell.; if(cell instanceof XSSFCell) { XSSFCell temp = (XSSFCell)cell; CTCell ctcell = temp.getCTCell(); if(ctcell!=null) { String v = ctcell.getV(); if(StringUtil.isNotEmpty(v)) { return v; } } } CellValue b = eva.evaluate(cell); if (b.getCellType() == 0) { return String.valueOf(b.getNumberValue()); } return b.getStringValue(); } case 3: default: return ""; case 4: return String.valueOf(cell.getBooleanCellValue()); } } }/** * 判斷指定的單元格是否是合並單元格 * * @param sheet * @param row * 行下標 * @param column * 列下標 * @return */ @SuppressWarnings("unused") public static boolean isMergedRegion(Sheet sheet, int row, int column) { int sheetMergeCount = sheet.getNumMergedRegions(); for (int i = 0; i < sheetMergeCount; i++) { org.apache.poi.ss.util.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; } /** * 判斷sheet頁中是否含有合並單元格 * @param sheet * @return * @return */ public static boolean hasMerged(Sheet sheet) { return sheet.getNumMergedRegions() > 0 ? true : false; } }
上面的方法是一個bug,循環的次數太多,導致效率太慢,我導入了6000行數據,做檢驗的過程中,就花費了8分鍾左右。這個也是大部分網上給出的建議。。。
我當時也在想能不能用數組或是集合的方式將合並的單元格緩存起來,然后進行對比判斷,這樣的話就會效率很高。
以下是官網上的方法:
//首先傳進來sheet,會將sheet中合並單元格的放在二維數組中,如果沒有單元格的數組中是null,如果這一行沒有合並單元格,則這一行的數組為null。
public static CellRangeAddress[][] buildMergedRangesMap( Sheet sheet ) { CellRangeAddress[][] mergedRanges = new CellRangeAddress[1][]; for ( final CellRangeAddress cellRangeAddress : sheet.getMergedRegions() ) { final int requiredHeight = cellRangeAddress.getLastRow() + 1; if ( mergedRanges.length < requiredHeight ) { CellRangeAddress[][] newArray = new CellRangeAddress[requiredHeight][]; System.arraycopy( mergedRanges, 0, newArray, 0, mergedRanges.length ); mergedRanges = newArray; } for ( int r = cellRangeAddress.getFirstRow(); r <= cellRangeAddress .getLastRow(); r++ ) { final int requiredWidth = cellRangeAddress.getLastColumn() + 1; CellRangeAddress[] rowMerged = mergedRanges[r]; if ( rowMerged == null ) { rowMerged = new CellRangeAddress[requiredWidth]; mergedRanges[r] = rowMerged; } else { final int rowMergedLength = rowMerged.length; if ( rowMergedLength < requiredWidth ) { final CellRangeAddress[] newRow = new CellRangeAddress[requiredWidth]; System.arraycopy( rowMerged, 0, newRow, 0, rowMergedLength ); mergedRanges[r] = newRow; rowMerged = newRow; } } Arrays.fill( rowMerged, cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn() + 1, cellRangeAddress ); } } return mergedRanges; }
下面是具體使用:
CellRangeAddress[][] cellRangeAddress=null;
//是否為合並單元格標志,判斷取單元格中的值的邏輯
boolean isMerge=false;
//判斷這個sheet存不存在合並單元格,如果不存在,在下面的每個單元格就不再進行判斷是不是單元格
boolean isSheetMerge=false;
//將合並單元格全部放在數組中
cellRangeAddress=ExcelToHtmlUtils.buildMergedRangesMap(sheetAt);
//是否為合並單元格標志,判斷取單元格中的值的邏輯
isMerge=false;
//判斷這個sheet存不存在合並單元格,如果不存在,在下面的每個單元格就不再進行判斷是不是單元格
isSheetMerge =(cellRangeAddress!=null)?true:false;
//如果sheet頁存在單元格的話,對判斷每個單元格是否 是合並單元格,否則不判斷 if(isSheetMerge){ //判斷是否為合並單元格,這里的邏輯如果不理解跟一下代碼就明白了。因為數組中只有合並單元格 if(rowIndex<cellRangeAddress.length){ if(!(cellRangeAddress[rowIndex]==null)){ if(cellIndex<cellRangeAddress[rowIndex].length){ if(!(cellRangeAddress[rowIndex][cellIndex]==null)){ isMerge=(cellRangeAddress[rowIndex][cellIndex]!=null); } } } } if(isMerge){ fRow = sheetAt.getRow(cellRangeAddress[rowIndex][cellIndex].getFirstRow()); fCell = fRow.getCell(cellRangeAddress[rowIndex][cellIndex].getFirstColumn()); cellvalue=this.getCellValue(fCell,(FormulaEvaluator)eva) ; //因為每次都需要進行判斷,所以默認設置為false isMerge=false; }else{ cellvalue = this.getCellValue(row.getCell(cellIndex), (FormulaEvaluator) eva); } }else{
//getCellValue方法在上面代碼中有,獲取單元格的值
cellvalue = this.getCellValue(row.getCell(cellIndex), (FormulaEvaluator) eva); }