POI事件模式读取Excel 2003文件
一.概述
1.?Excel 2003文件(即后綴為xls)是二進(jìn)制文件,存儲(chǔ)結(jié)構(gòu)為復(fù)合文檔,POI讀取xls文件有兩種方式
2. 事件模式適用于愿意學(xué)習(xí)一點(diǎn)低級(jí)API結(jié)構(gòu)的中間開發(fā)人員。它使用起來相對(duì)簡(jiǎn)單,但需要對(duì)Excel文件j結(jié)構(gòu)有個(gè)基本了解。
二. 存儲(chǔ)格式
2.1 Workbook document
1.Excel 2003文件稱之為一個(gè)Workbook文檔(Workbook document),一個(gè)Workbook document包含一個(gè)全局設(shè)置(Workbook globals)和至少一個(gè)Sheet
2.2 文檔流Workbook Stream
Excel 2003文檔(Workbook document)是以復(fù)合文檔的格式存儲(chǔ),復(fù)合文檔的原理就像一個(gè)文件系統(tǒng),Excel整個(gè)文件對(duì)應(yīng)的流文件稱為“ Workbook Stream”,Workbook stream又被分成了許多子流(Substream)2.3 子流SubStreams
文件流是按順序存儲(chǔ)的:三. 目錄結(jié)構(gòu)Directory
從上面我們知道以復(fù)合文檔為存儲(chǔ)格式的Excel 2003文件是以各種單獨(dú)的子流SubStreams,各種子流SubStreams安按照一定的順序構(gòu)成整個(gè)文檔流Workbook Stream. 那我們解析Excel 2003文件時(shí)怎么進(jìn)入各種子流SubStream呢? 這就要靠目錄結(jié)構(gòu)Directory了:3.1 目錄條目按序列舉
3.2 目錄條目結(jié)構(gòu)
目錄Directory將每個(gè)倉庫Storage的直接成員(倉庫或流)放在一個(gè)獨(dú)立的紅黑樹中
四. 記錄Record
Excel 2003文件中各種子流SubStreams會(huì)被解析為各種記錄Record,每種Record包含文檔中各種內(nèi)容或特定的數(shù)據(jù)- BOFRecord : 記錄了Workbook或一個(gè)sheet的開始
- EOFRecord : 記錄了Workbook或一個(gè)sheet的結(jié)尾
- STRecord : 記錄了Excel中所有文件大院個(gè)的文本值
- .......
4.1 Record解析順序
五. Workbook解析步驟
5.1 BOFRecord / EOFRecord
1.位置:org.apache.poi.hssf.record.BOFRecord、org.apache.poi.hssf.record.EOFRecord
2.BOFRecord表示W(wǎng)orkbook或一個(gè)sheet的開始,EOFRecord表示W(wǎng)orkbook或一個(gè)sheet的結(jié)尾
3.如圖:
5.2 FormatRecord
1. 位置: org.apache.poi.hssf.record.FormatRecord 2.?FormatRecord表示一個(gè)單元格樣式,每個(gè)單元格樣式對(duì)應(yīng)一個(gè)索引和單元格字符串 3. 如圖:5.3?ExtendedFormatRecord
1. 位置: org.apache.poi.hssf.record.ExtendedFormatRecord 2.?ExtendedFormatRecord記錄了一個(gè)單元格的屬性5.4?BoundSheetRecord
1. 位置:org.apache.poi.hssf.record.BoundSheetRecord 2.?BoundSheetRecord記錄了一個(gè)Sheet的名稱:5.5 SSTRecord
1.位置:org.apache.poi.hssf.record.SSTRecord
2.SSTRecord中存儲(chǔ)了在Excel中文本單元格中的文本值,文本單元格通過索引獲取文本值
3.如圖
六. WorkSheet解析步驟
6.1 BOFRecord/EOFRecord
1.? org.apache.poi.hssf.record.BOFRecord 2. type=16表示開始解析WorkSheet 3. 如圖:6.2 DimensionsRecord
1.位置:org.apache.poi.hssf.record.DimensionsRecord
2.DimensionsRecord存儲(chǔ)了一個(gè)sheet的行列范圍
| field_1_first_row | sheet中第一有效行行號(hào) |
| field_2_last_row | sheet中最后有效行行號(hào)+1 |
| field_3_first_col | sheet中第一有效列列號(hào) |
| field_4_last_col | sheet中最后有效列列號(hào)+1 |
3.如圖
6.3 ColumnInfoRecord
1.位置:org.apache.poi.hssf.record.ColumnInfoRecord
2.ColumnInfoRecord存儲(chǔ)了sheet中一列的信息
3.如圖:
6.4 RowRecord
1.? 位置: org.apache.poi.hssf.record.RowRecord 2. RowRecord記錄了當(dāng)前行行信息:6.5?LabelSSTRecord
1. 位置:org.apache.poi.hssf.record.LabelSSTRecord
2. LabelSSTRecord記錄了一個(gè)sheet中的文本單元格
3. 如圖:
| NumberRecord | 數(shù)值單元格 |
| LabelSSTRecord | 引用了SSTRecord中一個(gè)String類型的單元格值 |
| BoolErrRecord | 布爾或錯(cuò)誤單元格,根據(jù)屬性isError判斷是布爾還是錯(cuò)誤單元格 |
| FormulaRecord | 公式單元格 |
| BlankRecord | 空白單元格,單元格沒有值,但是有單元格樣式 |
| StringRecord | 存儲(chǔ)文本公式的緩存結(jié)果 |
| LabelRecord | 只讀,支持讀取直接存儲(chǔ)在單元格中的字符串,而不是存儲(chǔ)在SSTRecord中,除了讀取不要使用LabelRecord,應(yīng)該使用SSTRecord替代 |
6.6?NumberRecord
1.? 位置:? org.apache.poi.hssf.record.NumberRecord 2. NumberRecord記錄了一個(gè)Sheet中的數(shù)值單元格:數(shù)值或日期 3. 如圖:6.7?BoolErrRecord
1. 位置:?? org.apache.poi.hssf.record.BoolErrRecord 2.?BoolErrRecord記錄了一個(gè)Sheet中布爾單元格或錯(cuò)誤單元格 3. 如圖:6.8?FormulaRecord
1. 位置:? org.apache.poi.hssf.record.FormulaRecord 2.?FormulaRecord記錄了一個(gè)Sheet中的公式單元格 3. 如圖:6.9?BlankRecord
1. 位置:? org.apache.poi.hssf.record.BlankRecord 2. BlankRecord記錄了一個(gè)Sheet中一個(gè)空單元格:即單元格中沒有值,但是單元格有單元格樣式 3. 如圖:6.10 MergeCellsRecord
1.? 位置:? org.apache.poi.hssf.record.MergeCellsRecord 2.?MergeCellsRecord記錄了一個(gè)Sheet中一個(gè)合并單元格 3. 如圖:七. 解析步驟
使用POI事件模式解析Excel 2003文件,需要先將Excel 2003文件轉(zhuǎn)化為POI中POIFSFileSystem對(duì)象7.1 設(shè)置監(jiān)聽的Record
Excel XLS文檔最終被解析為一個(gè)個(gè)Record,如果某些Record設(shè)置了監(jiān)聽器,會(huì)觸發(fā)監(jiān)聽器事件 解析Excel XLS數(shù)據(jù)通常需要設(shè)置下面這些Record的監(jiān)聽器: BOFRecord.sid, // HSSFWorkbook、HSSFSheet的開始 EOFRecord.sid, // HSSFWorkbook、HSSFSheet的結(jié)束 BoundSheetRecord.sid, // BoundSheetRecord記錄了sheetName SSTRecord.sid, // SSTRecord記錄了所有Sheet的文本單元格的文本 DimensionsRecord.sid, // DimensionsRecord記錄了每個(gè)Sheet的有效起始結(jié)束行列索引 MergeCellsRecord.sid, // MergeCellsRecord記錄了每個(gè)Sheet中的合并單元格信息 ExtendedFormatRecord.sid, // ExtendedFormatRecord記錄了擴(kuò)展的單元格樣式 FormatRecord.sid, // FormatRecord記錄單元格樣式信息 ColumnInfoRecord.sid, // ColumnInfoRecord記錄了Sheet中列信息,如列是否隱藏 RowRecord.sid, // RowRecord記錄了Sheet中行信息,如行索引,行是否隱藏 BlankRecord.sid, // Sheet中空單元格,存在單元格樣式 BoolErrRecord.sid, // Sheet中布爾或錯(cuò)誤單元格 FormulaRecord.sid, // Sheet中公式單元格 LabelSSTRecord.sid, // Sheet中文本單元格 NumberRecord.sid // Sheet中數(shù)值單元格:數(shù)字單元格和日期單元格7.2 org.apache.poi.poifs.filesystem.POIFSFileSystem類
7.3 org.apache.poi.hssf.eventusermodel.HSSFListener
HSSFListener是與HSSFRequest和HSSFEventFactory一起使用的接口- 用戶應(yīng)該實(shí)現(xiàn)接口HSSFListener,創(chuàng)建一個(gè)自己的監(jiān)聽器類Workbook
- listener可以注冊(cè)到HSSFRequest實(shí)例request中,用于監(jiān)聽特定的Record
- 一個(gè)Record可以設(shè)置多個(gè)監(jiān)聽器,處理不同的事
7.4 org.apache.poi.hssf.eventusermodel.HSSFRequest
HSSFRequest中有一個(gè)Map,用于存儲(chǔ)所有特定Record的監(jiān)聽器,一個(gè)Record可以設(shè)置多個(gè)監(jiān)聽器| addListener(HSSFListener lsnr, short sid) | 為sid的記錄record注冊(cè)一個(gè)監(jiān)聽器lsnr |
| addListenerForAllRecords(HSSFListener lsnr) | 為org.apache.poi.hssf.record.Record包中所有的記錄注冊(cè)一個(gè)監(jiān)聽器lsnr 不推薦用這種方法,影響性能 |
| processRecord(Record rec) | 由HSSFEventFactory調(diào)用,處理記錄rec 記錄rec可能注冊(cè)了多個(gè)監(jiān)聽器,循環(huán)觸發(fā)每個(gè)注冊(cè)的監(jiān)聽器,處理記錄record |
7.5 org.apache.poi.hssf.eventusermodel.HSSFEventFactory
根據(jù)POIFSFileSystem實(shí)例解析Excel XLS文件的類| processWorkbookEvents(HSSFRequest req, POIFSFileSystem fs) | 將一個(gè)文件處理為基本的Record事件 @param req 一個(gè)HSSFRequest實(shí)例,記錄了Record的所有監(jiān)聽器 @param fs 包含WorkBook的POIFS文件系統(tǒng) |
| processWorkbookEvents(HSSFRequest req, DirectoryNode dir) | 將一個(gè)文件處理為基本的Record事件 @param req 一個(gè)HSSFRequest實(shí)例,記錄了Record的所有監(jiān)聽器 @param dir 包含WorkBook的DirectoryNode |
| processEvents(HSSFRequest req, InputStream in) | 將一個(gè)文件處理為基本的Record事件 @param req 一個(gè)HSSFRequest實(shí)例,記錄了Record的所有監(jiān)聽器 @param in?包含WorkBook的DirectoryNode的輸入流 |
| short abortableProcessWorkbookEvents(HSSFRequest req, POIFSFileSystem fs) | 將一個(gè)文件處理為基本的Record事件 返回?cái)?shù)值,如果監(jiān)聽器是繼承AbortableHSSFListener,返回值不為0,則不會(huì)觸發(fā)當(dāng)前記錄的其他監(jiān)聽器, 就會(huì)繼續(xù)處理下一個(gè)記錄 |
| short abortableProcessWorkbookEvents(HSSFRequest req, DirectoryNode dir) | 將一個(gè)文件處理為基本的Record事件 返回?cái)?shù)值,如果監(jiān)聽器是繼承AbortableHSSFListener,返回值不為0,則不會(huì)觸發(fā)當(dāng)前記錄的其他監(jiān)聽器, 就會(huì)繼續(xù)處理下一個(gè)記錄 |
| short abortableProcessEvents(HSSFRequest req, InputStream in) | 將一個(gè)文件處理為基本的Record事件 返回?cái)?shù)值,如果監(jiān)聽器是繼承AbortableHSSFListener,返回值不為0,則不會(huì)觸發(fā)當(dāng)前記錄的其他監(jiān)聽器, 就會(huì)繼續(xù)處理下一個(gè)記錄 |
八.一個(gè)事件模式實(shí)例
8.1 HSSFListener接口的實(shí)現(xiàn)類
package poi.hssf.event; import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.RowRecord; import org.apache.poi.hssf.record.SSTRecord; public class HSSFListenerImpl implements HSSFListener {private SSTRecord sstrec;/*** This method listens for incoming records and handles them as required.* @param record The record that was found while reading.*/public void processRecord(Record record) {switch (record.getSid()) {// the BOFRecord can represent either the beginning of a sheet or the workbookcase BOFRecord.sid:BOFRecord bof = (BOFRecord) record;if (bof.getType() == BOFRecord.TYPE_WORKBOOK) {System.out.println("處理 workbook");// assigned to the class level member} else if (bof.getType() == BOFRecord.TYPE_WORKSHEET) {System.out.println("處理sheet");}break;case BoundSheetRecord.sid:BoundSheetRecord bsr = (BoundSheetRecord) record;System.out.println("New sheet named: " + bsr.getSheetname());break;case RowRecord.sid:RowRecord rowrec = (RowRecord) record;System.out.println("Row found, first column at "+ rowrec.getFirstCol() + " last column at " + rowrec.getLastCol());break;case NumberRecord.sid:NumberRecord numrec = (NumberRecord) record;System.out.println("Cell found with value " + numrec.getValue()+ " at row " + numrec.getRow() + " and column " + numrec.getColumn());break;// SSTRecords store a array of unique strings used in Excel.case SSTRecord.sid:sstrec = (SSTRecord) record;for (int k = 0; k < sstrec.getNumUniqueStrings(); k++) {System.out.println("String table value " + k + " = " + sstrec.getString(k));}break;case LabelSSTRecord.sid:LabelSSTRecord lrec = (LabelSSTRecord) record;System.out.println("String cell found with value "+ sstrec.getString(lrec.getSSTIndex()));break;}} }
8.2 Test
packagepoi.hssf.event; importjava.io.FileInputStream; importjava.io.IOException; importjava.io.InputStream; importorg.apache.poi.hssf.eventusermodel.HSSFEventFactory; importorg.apache.poi.hssf.eventusermodel.HSSFRequest; importorg.apache.poi.poifs.filesystem.POIFSFileSystem; publicclass TestEventAPI {publicstatic void main(String[] args) throwsIOException {FileInputStream fin = newFileInputStream("C:\\Users\\Administrator\\Desktop\\測(cè)試.xls");try{POIFSFileSystem poifs = newPOIFSFileSystem(fin);try{// 從流中獲取Excel的WorkBook流InputStream workBookInputStream = poifs.createDocumentInputStream("Workbook");try{HSSFRequest hssfRequest = newHSSFRequest();// 為所有的record注冊(cè)一個(gè)監(jiān)聽器hssfRequest.addListenerForAllRecords(newHSSFListenerImpl());// 創(chuàng)建事件工廠HSSFEventFactory factory = newHSSFEventFactory();// 根據(jù)WorkBook輸入流處理所有事件factory.processEvents(hssfRequest, workBookInputStream);}finally{workBookInputStream.close();}}finally{poifs.close();}}finally{// 一旦所有的監(jiān)聽器處理完成,關(guān)閉文件輸入流fin.close();}} }總結(jié)
以上是生活随笔為你收集整理的POI事件模式读取Excel 2003文件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS 开发AVFoundation系统
- 下一篇: 总结——》【养生之道】