依据了https://blog.csdn.net/u013488171/article/details/78184545的帖子,感谢作者小逝的无私分享。
本人亲测导入4万条数据用时32分钟,因为有我自己本人项目的数据校验,大家的时间很可能不一样。
备注:我应用的时候出了这样的错误,最后没用这个方法,我的另一个帖子:https://www.cnblogs.com/daguozb/p/10043986.html,解析路径错误。
用到的jar包;
bios-poi-ooxml-3.9.jar
导入的思路见原博客,我说下我应用的文件建立思路:建立一个作为工具类的:抽象类BigDataParseExcelUtil,在抽象类中实现了excel的转换(转换过程可以不看);对外展现接口process(String filename)来传入文件路径,并有个抽象方法对外迭代输出excel每行数据。
然后在你的方法里用匿名内部类的形式使用,实现抽象方法optRows,完成自己的操作。
代码如下:
抽象类BigDataParseExcelUtil
package com.iss.itms.util.excel; import java.io.InputStream; import java.sql.SQLException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Iterator; import java.util.List; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.time.DateUtils; import org.apache.poi3.openxml4j.opc.OPCPackage; import org.apache.poi3.xssf.eventusermodel.XSSFReader; import org.apache.poi3.xssf.model.SharedStringsTable; import org.apache.poi3.xssf.usermodel.XSSFRichTextString; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import com.toft.utils.ToftLogger; /** * XSSF and SAX (Event API) */ public abstract class BigDataParseExcelUtil extends DefaultHandler { private SharedStringsTable sst; private String lastContents; private boolean nextIsString; private int sheetIndex = -1; private List<String> rowlist = new ArrayList<String>(); private int curRow = 0; // 当前行 private int curCol = 0; // 当前列索引 private int preCol = 0; // 上一列列索引 private int titleRow = 0; // 标题行,一般情况下为0 private int rowsize = 0; // 列数 private List excelList=new ArrayList(); //excel全部转换为list // excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型 public abstract void optRows(int sheetIndex, int curRow, List<String> rowlist,List excelList) throws SQLException, Exception; // 只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3 /** * * @param filename * @param sheetId * sheetId为要遍历的sheet索引,从1开始,1-3 * @throws Exception */ public void processOneSheet(String filename, int sheetId) throws Exception { OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader(pkg); SharedStringsTable sst = r.getSharedStringsTable(); XMLReader parser = fetchSheetParser(sst); // rId2 found by processing the Workbook // 根据 rId# 或 rSheet# 查找sheet InputStream sheet2 = r.getSheet("rId" + sheetId); sheetIndex++; InputSource sheetSource = new InputSource(sheet2); parser.parse(sheetSource); sheet2.close(); } public void characters(char[] ch, int start, int length) throws SAXException { // 得到单元格内容的值 lastContents += new String(ch, start, length); } /** * 遍历 excel 文件 */ public void process(String filename) throws Exception { // String fileString="C:\Users\hp\Desktop\新建\model_ebankcertificate.xlsx"; ToftLogger.info("---process(String filename)方法的filename值为:"+filename); OPCPackage pkg = OPCPackage.open(filename); XSSFReader r = new XSSFReader(pkg); SharedStringsTable sst = r.getSharedStringsTable(); XMLReader parser = fetchSheetParser(sst); Iterator<InputStream> sheets = r.getSheetsData(); while (sheets.hasNext()) { curRow = 0; sheetIndex++; InputStream sheet = sheets.next(); InputSource sheetSource = new InputSource(sheet); parser.parse(sheetSource); sheet.close(); } } public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException { XMLReader parser = XMLReaderFactory.createXMLReader(); // .createXMLReader("org.apache.xerces.parsers.SAXParser"); this.sst = sst; parser.setContentHandler(this); return parser; } public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { // c => 单元格 if (name.equals("c")) { // 如果下一个元素是 SST 的索引,则将nextIsString标记为true String cellType = attributes.getValue("t"); String rowStr = attributes.getValue("r"); curCol = this.getRowIndex(rowStr); if (cellType != null && cellType.equals("s")) { nextIsString = true; } else { nextIsString = false; } } // 置空 lastContents = ""; } public void endElement(String uri, String localName, String name) throws SAXException { // 根据SST的索引值的到单元格的真正要存储的字符串 // 这时characters()方法可能会被调用多次 if (nextIsString) { try { int idx = Integer.parseInt(lastContents); lastContents = new XSSFRichTextString(sst.getEntryAt(idx)) .toString(); } catch (Exception e) { } } // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引 // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符 if (name.equals("v")) { String value = lastContents.trim(); value = value.equals("") ? " " : value; int cols = curCol - preCol; if (cols > 1) { for (int i = 0; i < cols - 1; i++) { rowlist.add(preCol, ""); } } preCol = curCol; rowlist.add(curCol - 1, value); } else { // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法 if (name.equals("row")) { int tmpCols = rowlist.size(); if (curRow > this.titleRow && tmpCols < this.rowsize) { for (int i = 0; i < this.rowsize - tmpCols; i++) { rowlist.add(rowlist.size(), ""); } } try { optRows(sheetIndex, curRow, rowlist,excelList); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } if (curRow == this.titleRow) { this.rowsize = rowlist.size(); } rowlist.clear(); curRow++; curCol = 0; preCol = 0; } } } // 得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引, // 如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行 public int getRowIndex(String rowStr) { rowStr = rowStr.replaceAll("[^A-Z]", ""); byte[] rowAbc = rowStr.getBytes(); int len = rowAbc.length; float num = 0; for (int i = 0; i < len; i++) { num += (rowAbc[i] - 'A' + 1) * Math.pow(26, len - i - 1); } return (int) num; } public void text(int t){ Calendar c = new GregorianCalendar(1900,0,0); Date d = c.getTime(); Date _d = DateUtils.addDays(d, t); System.out.println(_d.toLocaleString()); } public List getExcelList() { return this.excelList; } // 测试使用 public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); BigDataParseExcelUtil xlx = new BigDataParseExcelUtil() { @Override public void optRows(int sheetIndex, int curRow, List<String> rowlist,List excelList) throws SQLException { System.out.println(rowlist); if(!"证书到期日*".equals(rowlist.get(6))){ int parseInt = Integer.parseInt(rowlist.get(6)); System.out.println(parseInt); text(parseInt-1); } } }; // xlx.process("C:\Users\winitadmin\导出123.xlsx"); xlx.process("C:\Users\hp\Desktop\model_ebankcertificatedfs.xlsx"); long end = System.currentTimeMillis(); System.out.println((end - start) / 1000); } }
我对BigDataParseExcelUtil的应用,上面代码只是实现了excel的解析和转换,我们要把解析好的数据插入到数据库,完成操作。
public void impdata() throws Exception{ //匿名内部类,实现工具类的操作方法,完成导入功能 BigDataParseExcelUtil xlx = new BigDataParseExcelUtil() { List<String> onlyUCode=new ArrayList<String>();//记录导入文件的Code,避免重复 @Override public void optRows(int sheetIndex, int curRow, List<String> rowlist,List excelList) throws Exception { ToftLogger.info("---进入方法optRows-----"); //excelList,onlyUCode是我自己项目用的,你们自决定去留。去掉的话在工具类里也改下 impdataOperation(sheetIndex,curRow,rowlist,excelList,onlyUCode); } }; String fileName = this.getContext().getAttribute("fileName").toString(); xlx.process(fileName); List excelList = xlx.getExcelList();//我在impdataOperation方法里把excle的数据全部放到了excelList里,所以这里能get到 }
上面impdataOperation方法是我完成自己项目实现的方法,不贴了;一般就是校验个列数据。
注意:1、什么时候知道excel导入完成?
我也不知道,所以我就在我上面加了excelList属性,在impdataOperation方法中校验完成就给excelList添加一条,知道最后一条,到List excelList = xlx.getExcelList();就获得了全部的数据。大家有好的方法希望留言。
先这样,有问题大家多评论。