poi sax 方式 匯入excel海量資料

2021-06-21 20:57:35 字數 3979 閱讀 5030

這幾天做excel匯入資料.剛開始使用jxl匯入03版的,因為資料量超過65536,03版裝不下,所以就用poi來支援07版的.

直接網上copy了個**過去,搞了2條資料測試下成功了.

結果在匯入正式資料的時候,才20m的excel檔案就記憶體溢位了.網上搜了下,這情況很常見,需要使用sax方式來解析才可以.

但是在使用中,歷經磨難,所以記錄下來,以增強記憶.

還有好幾個問題沒解決,也一起記錄下來,看哪位幫忙解決.

**總共三段. 1.解析.2.抽象介面.3.業務類

1.解析類,繼承defaulthandler

/**

* 抽象excel2007讀取器,excel2007的底層資料結構是xml檔案,採用sax的事件驅動的方法解析

* xml,需要繼承defaulthandler,在遇到檔案內容時,事件會觸發,這種做法可以大大降低

* 記憶體的耗費,特別使用於大資料量的檔案。

* */

public class excel2007reader extends defaulthandler

/*** 根據sheetid 解析sheet

* @param stream

* @param sheetid

* @throws exception

*/public void processonesheetbyindex(string filename,int sheetid) throws exception

/*** 根據sheet名稱,解析sheet

* @param stream

* @param name

* @throws exception

*/public void process(inputstream stream) throws exception

} public xmlreader fetchsheetparser(sharedstringstable sst)

throws saxexception

public void startelement(string uri, string localname, string name,

attributes attributes) throws saxexception else

string r = attributes.getvalue("r");

int firstdigit = -1;

for (int c = 0; c < r.length(); ++c)

} thiscolumnindex = nametocolumn(r.substring(0, firstdigit)); ;

} else if (name.equals("row"))

}else if (name.equals("dimension"))

// 置空

lastcontents = "";

} public void endelement(string uri, string localname, string name)

throws saxexception catch (exception e)

} if ("v".equals(name)) else }}

/**

* 從列名轉換為列索引

* @param name

* @return

*/ private static int nametocolumn(string name)

return column;

} @suppresswarnings("unused")

private void optrows(int sheetindex,int currow, listrowlist, int total2)

system.out.println("");

} public static void main(string args) throws exception

}

2.介面

public inte***ce irowreader
3.業務類

public class contracttempmanagerimpl implements irowreader else

endtime = new date().gettime();

system.out.println("插入所需時間為 : " + (endtime - begintime)/1000 + "秒!");

}/**

* 實現介面

* @param sheetindex

* @param currow 當前行

* @param rowlist 行結果

* @param total 總行數()

* @param sheetname sheet名稱

* @throws uiexception

*/public void getrows(int sheetindex, int currow, listrowlist,int total,string sheetname) throws uiexception else if(sheetname.equals("合同對方"))else

}}

**說明

1.解析裡面的,大部分都是網上copy的,很多都不太懂.主要是要繼承defaulthandler, 和重寫startelement,endelement.

然後在 endelement中呼叫業務類的操作.

這裡說下我遇到的問題和解決方法及沒有解決的:

1. 多個模版,每個模版多個sheet,解析類怎麼公用.

解決: 在解析類中用了個介面的屬性rowreader,endelement()呼叫rowreader.getrows(),然後業務類實現這個介面,就解決了多個模版復用**的問題.

然後在getrows()中將sheet名稱作為引數傳遞,則在同個業務類中根據sheet不同執行不同操作也解決.

實踐中才更能理解面向介面程式設計的意義.

2.根據sheet名稱解析指定sheet

解決: 網上沒找到根據sheet名稱解析的,都是根據id和全部解析.所以就用了全部解析,然後拿到sheet名稱.

3.獲取sheet的總行數.

解決:因為是用的批處理,業務類的list每2000條提交一次,最後一批可能不到2000,所以需要總行數用來判斷是否最後一批,

這個很簡單.**中dimension型別,getnumber()方法.(這個方法沒看太懂,不過無所謂了.)

4.空值的處理

解決:如果excel中某列為空,那麼解析時候是讀不到的,因為xml中根本就沒有這列.(將excel字尾名修改為.zip,即可看xml檔案)

網上copy了個方法paddingnullcell(). 應該是根據當前列號和上個列號做比較,來填充.

5.最後一列空值的處理

解決:上面說網上copy的方法解決了中間的空列,但是最後一列空的話卻沒有解決,所以我就自己寫了個.

在startelement()中,第一行的時候,獲得總列數(第一行是標題,以標題列數字置)

在endelement()中,行結束前,先看list的size是否是總列數,如果不是則補充

6.數字 3995.992, 讀取到為 3995.9920000000002

未解決: 這個在編輯欄看到也是3995.992,並且設定很多小數字後,還是3995.9920000000000 ,沒有出現2

在修改為zip檢視xml檔案中,xml顯示為3995.9920000000002

很莫名其妙,設定格式為文字,並且雙擊然後讓單元格前面出現文字標識那樣,則xml中正常.

網上找了很多,也沒找到解決辦法. 例如擷取,正則什麼的, 都不適用.

最後只有用最笨的辦法,手動一列一列的 分列為文字格式.

解析xml不是很懂,暈暈乎乎的就拿來用了.一定要好好補習基礎.

ok.就這麼多了.第一次寫部落格,希望以後能堅持.

Excel資料匯入

excel資料匯入 你hold住麼 一 在本篇將帶領大家一同了解 匯入excel流程和問題解決方案 需要注意的是在server端的web config 中新增這幾行 ps 中value 是根據自己的專案中的資料夾的命名而定,可參考以下截圖 由於在server的配置檔案的檔名不一致。找不excel的x...

excel匯入匯出

匯出 yii框架中 header content disposition attachment filename 123.xls arr connection createcommand select from recruit queryall array this db get recruit r...

Excel資料匯入

private void button3 click object sender,eventargs e 連線excel的連線字串,excel2007版本以上的 hdr yes代表第一行是列名 string strconn provider microsoft.ace.oledb.12.0 data...