我可以使用事件模型POI成功读取Excel文件(.xls)。我没有使用usermodel(org.apache.poi.ss.usermodel),而是使用Event API来处理xls和xlsx文件(以解决内存占用问题)。但是,在读取包含多个工作表的.xls文件时,只会读取第一个工作表。其他工作表被忽略。
我正在实现HSSFListener并覆盖xls文件的processRecord(记录记录)方法。
以下是我的代码部分:
/**
* Main HSSFListener method for xls. It processes events and creates a RuntimeRecord to put into the DataPool.
*/
public void processRecord(Record record) {
int thisRow = -1;
String thisStr = null;
switch (record.getSid()) {
case BoundSheetRecord.sid:
boundSheetRecords.add(record);
break;
case BOFRecord.sid:
BOFRecord br = (BOFRecord)record;
if(br.getType() == BOFRecord.TYPE_WORKSHEET) {
// Works by ordering the BSRs by the location of their BOFRecords, and then knowing that we
// process BOFRecords in byte offset order
if(orderedBSRs == null) {
orderedBSRs = BoundSheetRecord.orderByBofPosition(boundSheetRecords);
}
// Check the existence of sheets
if(sheetIndex == 0) {
for(int i=0;i<excelSheetList.length;i++) {
boolean found = false;
if(this.getExcelSheetSpecification().equals(MSExcelAdapter.USE_WORKSHEET_NAME)) {
for(BoundSheetRecord rec : orderedBSRs) {
int len = rec.getSheetname().length();
if(len > 31)
this.warning("processRecord()","The length of sheet: " + rec.getSheetname() + " has more than 31 characters. Please change the name of the sheet, save the file and try again.");
}
}
if(this.getExcelSheetSpecification().equals(MSExcelAdapter.USE_WORKSHEET_NUMBER)) {
int sheetNo = Integer.parseInt(excelSheetList[i]);
if(sheetNo > 0 && sheetNo <= orderedBSRs.length) {
found = true;
}
} else {
for(int j=0;j<orderedBSRs.length;j++) {
if(this.getExcelSheetSpecification().equals(MSExcelAdapter.USE_WORKSHEET_NAME)) {
String sheetName = ((BoundSheetRecord) boundSheetRecords.get(j)).getSheetname();
if(excelSheetList[i].equals(sheetName)) {
found = true;
break;
}
}
}
}
if(!found)
this.error("processRecord()","Sheet: " + excelSheetList[i] + " does not exist.");
}
}
readCurrentSheet = true;
sheetIndex++;
System.out.println(sheetIndex);
if(this.getExcelSheetSpecification().equals(MSExcelAdapter.USE_WORKSHEET_NAME)) {
String sheetName = ((BoundSheetRecord) boundSheetRecords.get(sheetIndex-1)).getSheetname();
if(!canRead(sheetName)) {
readCurrentSheet = false;
}
} else {
if(!canRead(sheetIndex + "")) {
readCurrentSheet = false;
}
}
}
break;
case SSTRecord.sid:
sstRecord = (SSTRecord) record;
break;
case BlankRecord.sid:
BlankRecord brec = (BlankRecord) record;
thisRow = brec.getRow();
thisStr = null;
values.add(thisStr);
columnCount++;
break;
case FormulaRecord.sid:
FormulaRecord frec = (FormulaRecord) record;
thisRow = frec.getRow();
if(Double.isNaN( frec.getValue() )) {
// Formula result is a string
// This is stored in the next record
outputNextStringRecord = true;
nextRow = frec.getRow();
} else {
thisStr = formatListener.formatNumberDateCell(frec);
}
break;
case StringRecord.sid:
if(outputNextStringRecord) {
// String for formula
StringRecord srec = (StringRecord)record;
thisStr = srec.getString();
thisRow = nextRow;
outputNextStringRecord = false;
}
break;
case LabelSSTRecord.sid:
if(readCurrentSheet) {
LabelSSTRecord lsrec = (LabelSSTRecord) record;
thisRow = lsrec.getRow() + 1;
if(rowNumberList.contains(thisRow + "") ||
(rowNumberList.contains(END_OF_ROWS) && thisRow >= secondLastRow)) {
if(sstRecord == null) {
thisStr = "(No SST Record, can't identify string)";
} else {
thisStr = sstRecord.getString(lsrec.getSSTIndex()).toString();
}
}
}
break;
case NumberRecord.sid:
if(readCurrentSheet) {
NumberRecord numrec = (NumberRecord) record;
thisRow = numrec.getRow() + 1;
if(rowNumberList.contains(thisRow + "") ||
(rowNumberList.contains(END_OF_ROWS) && thisRow >= secondLastRow)) {
// No need to format.
// thisStr = formatListener.formatNumberDateCell(numrec); // Format
thisStr = String.valueOf(numrec.getValue());
}
}
break;
default:
break;
}
// Handle missing column
if(record instanceof MissingCellDummyRecord) {
thisStr = "";
}
// If we got something to print out, do so
if(thisStr != null) {
values.add(thisStr);
columnCount++;
}
// Handle end of row
if(record instanceof LastCellOfRowDummyRecord) {
if(readCurrentSheet) {
int currentRow = ((LastCellOfRowDummyRecord) record).getRow() + 1;
if(rowsReadSet.add(String.valueOf(currentRow))) {
if(processTestData) {
try {
int dpSize = this.getOutputDP().getSize();
if(dpSize < 1000 &&
(rowNumberList.contains(currentRow + "") ||
(rowNumberList.contains(END_OF_ROWS) && currentRow >= secondLastRow))) {
for(int i=columnCount; i<this.getConfigRecord().size(); i++) {
values.add(null); // Add empty string for missing columns
}
RuntimeRecord resultRecord = this.createRuntimeRecord(values);
this.fireRecordCreatedEvent(resultRecord);
this.putNextRecord(resultRecord);
}
} catch (Exception e) {
this.error("processRecord()",e.getMessage());
this.fireRecordCreationFailedEvent(e.getMessage(), e.getMessage());
}
} else {
try {
if(rowNumberList.contains(currentRow + "") || (rowNumberList.contains(END_OF_ROWS) && currentRow >= secondLastRow)) {
for(int i=columnCount; i<this.getConfigRecord().size(); i++) {
values.add(null); // Add empty string for missing columns
}
RuntimeRecord resultRecord = this.createRuntimeRecord(values);
this.fireRecordCreatedEvent(resultRecord);
this.putNextRecord(resultRecord);
}
} catch (Exception e) {
this.error("processRecord()",e.getMessage());
this.fireRecordCreationFailedEvent(e.getMessage(), e.getMessage());
}
}
}
values.removeAllElements();
columnCount = 0;
}
}
}
以下是注册侦听器的方法:
private void readxls() throws FileNotFoundException, IOException {
POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(this.getFileName()));
MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
formatListener = new FormatTrackingHSSFListener(listener);
HSSFEventFactory factory = new HSSFEventFactory();
HSSFRequest request = new HSSFRequest();
request.addListenerForAllRecords(formatListener);
rowsReadSet.clear();
factory.processWorkbookEvents(request, fs);
}
当我通过添加一些断点进行调试时,我注意到它实际上将列值添加到我的values
Vector中。但是,以下条件永远不会与第二张相匹配。
if(record instanceof LastCellOfRowDummyRecord) {
...
}
如何摆脱这个问题?我想阅读Excel文件(.xls)中的所有工作表。我正在使用Apache POI 3.11-20141221和JDK7。