JAVA解析Excel方式二:利用POI的事件驱动模型解析excel内容,强大。


1.解析类

public class ProcessExcelUtil {
/**
* 解析每个sheet页数据
*
* @param styles
* @param strings
* @param sheetInputStream
* @param saxSheetContentsHandler
* @throws Exception
*/
private static void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream, SaxSheetContentsHandler saxSheetContentsHandler)
throws Exception {
try {
XMLReader sheetParser = SAXHelper.newXMLReader();
sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, saxSheetContentsHandler, false));
sheetParser.parse(new InputSource(sheetInputStream));
} catch (Exception e) {
throw e;
} finally {
if (Objects.nonNull(sheetInputStream)) {
sheetInputStream.close();
}
}
}

public static void main(String[] args) throws Exception {
Map<Integer, List<Map<String, String>>> dataMap = new HashMap<>();
OPCPackage pkg = null;
InputStream in = new FileInputStream("E:\\test.xlsx");
pkg = OPCPackage.open(in);
XSSFReader xssfReader = new XSSFReader(pkg);
StylesTable styles = xssfReader.getStylesTable();
ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
Iterator<InputStream> iterators = xssfReader.getSheetsData();
int sheetCount = 1;
while (iterators.hasNext()) {
List<Map<String, String>> dataListMap = new ArrayList<>();
SaxSheetContentsHandler sheetHandler = new SaxSheetContentsHandler(dataListMap, 0, 0, -1);
processSheet(styles, strings, iterators.next(), sheetHandler);
dataMap.put(Integer.valueOf(sheetCount), dataListMap);
sheetCount = sheetCount + 1;
}
for(Map.Entry<Integer,List<Map<String,String>>> map :dataMap.entrySet()){ //迭代每个sheet
List<Map<String,String>> titleRow=map.getValue();
for(Map<String,String> cellMap :titleRow){ //迭代sheet的每行数据,cellMap是每行数据
//cellMap保存的是Excel每行的键值对例如{"列名":值}:{"A": value,"B": value}
System.out.println(cellMap.entrySet());
}
}
}
}
2.自定义SAX装载工类
@Data
public class SaxSheetContentsHandler implements XSSFSheetXMLHandler.SheetContentsHandler {
Logger logger= LoggerFactory.getLogger(SaxSheetContentsHandler.class);
//数据单元
private Map<String,String> cellMap=new HashMap<>();
//数据记录,按行记录
private List<Map<String,String>> cellDataListMap;
//解析开始行
private int startRow=0;
//解析开始列
private int startCol=0;
//当前列
private int currentCol=0;
//读取数据行(默认为-1不做限制)
private int limit=-1;

/**
* 构造器
* @param cellDataListMap
* @param startRow
* @param startCol
*/
public SaxSheetContentsHandler(List<Map<String,String>> cellDataListMap, int startRow, int startCol,int limit){
this.cellDataListMap=cellDataListMap;
this.startCol=startCol;
this.startRow=startRow;
this.limit=limit;
}

@Override
public void startRow(int rowNum) {
if(limit==-1){
if(rowNum<startRow){
return;
}
}else {
if(rowNum<startRow || rowNum>limit){
return;
}
}
cellMap.clear();
}

@Override
public void endRow(int rowNum) {
if(limit==-1){
if(rowNum<startRow){

return;
}
}else if(rowNum<startRow || rowNum>limit) { //用来判断从第几行开始读取,如果当前行小于开始行则需终止程序。
currentCol=0;
return;
}
if(!cellMap.isEmpty()){
Map<String,String> rowMap = null;
try {
rowMap = (Map<String, String>) CloneUtils.clone(cellMap);
cellDataListMap.add(rowMap);
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
currentCol=0;
}

/**
*
* @param cellReference 列名 例如A,B,C等
* @param formattedValue 单元格值 对应每个单元格的值, [^A-Za-z]:匹配所有非字母的都用""
* 代替,因为多行Excel的列明是:A1,B1,C1,....D10等,匹配替换后每行的列名就是A,B,C等。
* 此方法用解析每一个cell的值
* @param comment
*/
@Override
public void cell(String cellReference, String formattedValue, XSSFComment comment) {
currentCol=currentCol+1;
if(currentCol>=startCol){
cellMap.put( cellReference.replaceAll("[^A-Za-z]",""),formattedValue);
}
return;

}

@Override
public void headerFooter(String text, boolean isHeader, String tagName) {
logger.debug("text: {},isHeader: {},tagName : {}",text,isHeader,tagName);
}
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM