POI驱动模式读取Excel2007

  • 项目需要进行导入优化的时候,因为之前用poi旧版本读取excel时效率比较慢,后来了解的poi的驱动模式后,准备用来改造导入方法.在大批量数据面前效率提升比较明显(几百几千行数据时效率提供微弱) .
  • 在封装Excel 读取工具类时,对别人的代码进行了一定的包装(包装代码如下) ,只要继承该类 覆写操作行方法,就可以取到自己期望的属性.
  • 后来发现因为Excel中有空值的时候,不能生成成对的标签,所以在读取含有空的单元格时 不能满足特定的需求. 所以对该类又进行了封装.
  • 感兴趣的可以自己对excel2007生成xml文件进行阅读,发现规律修改下边的方法.或者可以直接下载
  • https://download.csdn.net/download/x308561498/11011654

  • 测试类:
import java.io.File;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

public class ImportExample {
	public final  static  Logger logger=LoggerFactory.getLogger(ImportExample.class);
/**
  读取内容 如下
	 姓名,分数,备注
	张三,80,及格
	李四,60,
	王五,100,优秀
 * @throws Exception 
 */
//将excel数据读入JsonArray中
public static void main(String[] args) throws Exception {
		File  file =new File("F:/info.xlsx");
	    InfoExcelRead  infoExcel=new InfoExcelRead();
	     infoExcel.setReadLength(3);//设置读取列
	     infoExcel.readExcel2007(file);
	     logger.info(new Gson().toJson(infoExcel.getJos()));
	}
}
class   InfoExcelRead  extends  ImportExcelMap{
	 private  JsonArray  jos=new JsonArray();
	public JsonArray getJos() {
		return jos;
	}
	public void setJos(JsonArray jos) {
		this.jos = jos;
	}
	@Override
	  public void optRow(int sheetIndex, int curRow, Map<Integer, String> rowMap) {
             if (curRow>0) {  //跳过列头
            	 JsonObject  jo=new  JsonObject();
				 jo.addProperty("name", rowMap.get(1));
				 jo.addProperty("score", rowMap.get(2));
				 jo.addProperty("remarks", rowMap.get(3));
				 jos.add(jo);
			 }
	 }
}

  • 测试结果如下:在这里插入图片描述

~未处理空格的Excel工具类

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.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;

public class ImportExcelUtil 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 String col = "";
    
    public  void  readExcel2007(byte[] bytes)  throws Exception{
    	 ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
    	 readExcel2007(byteArrayInputStream);
    }
    
    public  void  readExcel2007(String path)  throws Exception{
    	OPCPackage pkg = OPCPackage.open(path,PackageAccess.READ);
    	readOneSheet(pkg);
    }
    
    public  void  readExcel2007(InputStream inputStream)   throws Exception{
       try {
    	OPCPackage pkg = OPCPackage.open(inputStream);
    	readOneSheet(pkg);
		} catch (Exception e) {
			 e.printStackTrace();
		}finally{
			
			if (inputStream!=null) {
				inputStream.close();
			}
			
		}
    }
    
    public  void  readExcel2007(File file)throws Exception{
    	OPCPackage pkg = OPCPackage.open(file,PackageAccess.READ);
    	readOneSheet(pkg);
    }
    
    
       
    /**  
     * 直接读取第一个工作簿 
     * @param path  
     */  
    public void readOneSheet(OPCPackage  pkg) throws Exception {
        XSSFReader r = new XSSFReader(pkg);
        SharedStringsTable sst = r.getSharedStringsTable(); 
        XMLReader parser = fetchSheetParser(sst);
        InputStream sheet = r.getSheet("rId1");
        InputSource sheetSource = new InputSource(sheet);
        parser.parse(sheetSource);
        sheet.close();
    }
       
       
    /**  
     * 该方法自动被调用,每读一行调用一次,在方法中写自己的业务逻辑即可  
     * @param sheetIndex 工作簿序号 
     * @param curRow 处理到第几行 
     * @param rowList 当前数据行的数据集合 
     */  
    public void optRow(int sheetIndex, int curRow, List<String> rowList) {
    	System.out.println("-------curRow----------"+curRow);
        String temp = "";   
        for(String str : rowList) {
            temp += str + "_";
        }
        
       System.out.println("-------curValue----------:"+temp);   
    }
       
    /**
     * XML解析器   
     * @param sst
     * @return
     * @throws SAXException
     */
    public XMLReader fetchSheetParser(SharedStringsTable sst) throws SAXException {
        XMLReader parser = XMLReaderFactory   
                .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")) {
        	col = attributes.getValue("r");
            // 如果下一个元素是 SST 的索引,则将nextIsString标记为true  
            String cellType = attributes.getValue("t");   
            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();
                nextIsString = false;
            } catch (Exception e) {
            	e.printStackTrace();
            }
        }
  
        // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引 
        // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符  
        if (name.equals("v")) {
            String value = lastContents.trim();
            rowlist.add(curCol, value);
            curCol++;
        } else {
            // 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法  
            if (name.equals("row")) {
                optRow(sheetIndex, curRow, rowlist);
                rowlist.clear();
                curRow++;
                curCol = 0;
            }
        }
    }
  
    public void characters(char[] ch, int start, int length)   
            throws SAXException {
        // 得到单元格内容的值  
        lastContents += new String(ch, start, length);   
    }
}


maven pom如下

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>3.9</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.9</version>
</dependency>
<dependency>
    <groupId>xerces</groupId>
    <artifactId>xerces</artifactId>
    <version>2.4.0</version>
</dependency>  

因为工具类中引用gson,slf4j可以直接删除(只是用来输出日志显示用的)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章