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可以直接刪除(只是用來輸出日誌顯示用的)

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