Apply patch from bug #51460 (with some related generics tweaks) - Improve HSSF performance when loading very long rows, by switching the CellValue array to an iterator

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1141970 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Nick Burch 2011-07-01 16:16:55 +00:00
parent 1970d1156a
commit e11c26c29b
6 changed files with 105 additions and 17 deletions

View File

@ -34,7 +34,8 @@
<changes> <changes>
<release version="3.8-beta4" date="2011-??-??"> <release version="3.8-beta4" date="2011-??-??">
<action dev="poi-developers" type="add">51444 - Prevent corrupted output when saving files created by LibreOffice 3.3 </action> <action dev="poi-developers" type="add">51460 - Improve HSSF performance when loading very long rows, by switching the CellValue array to an iterator</action>
<action dev="poi-developers" type="fix">51444 - Prevent corrupted output when saving files created by LibreOffice 3.3 </action>
<action dev="poi-developers" type="add">51422 - Support using RecalcIdRecord to trigger a full formula recalculation on load </action> <action dev="poi-developers" type="add">51422 - Support using RecalcIdRecord to trigger a full formula recalculation on load </action>
<action dev="poi-developers" type="add">50474 - Example demonstrating how to update Excel workbook embedded in a WordprocessingML document </action> <action dev="poi-developers" type="add">50474 - Example demonstrating how to update Excel workbook embedded in a WordprocessingML document </action>
<action dev="poi-developers" type="fix">51431 - Avoid IndexOutOfBoundException when removing freeze panes in XSSF </action> <action dev="poi-developers" type="fix">51431 - Avoid IndexOutOfBoundException when removing freeze panes in XSSF </action>

View File

@ -360,13 +360,13 @@ public final class InternalSheet {
private static final class RecordCloner implements RecordVisitor { private static final class RecordCloner implements RecordVisitor {
private final List<RecordBase> _destList; private final List<Record> _destList;
public RecordCloner(List<RecordBase> destList) { public RecordCloner(List<Record> destList) {
_destList = destList; _destList = destList;
} }
public void visitRecord(Record r) { public void visitRecord(Record r) {
_destList.add((RecordBase)r.clone()); _destList.add((Record)r.clone());
} }
} }
@ -378,7 +378,7 @@ public final class InternalSheet {
* belongs to a sheet. * belongs to a sheet.
*/ */
public InternalSheet cloneSheet() { public InternalSheet cloneSheet() {
List<RecordBase> clonedRecords = new ArrayList<RecordBase>(_records.size()); List<Record> clonedRecords = new ArrayList<Record>(_records.size());
for (int i = 0; i < _records.size(); i++) { for (int i = 0; i < _records.size(); i++) {
RecordBase rb = _records.get(i); RecordBase rb = _records.get(i);
if (rb instanceof RecordAggregate) { if (rb instanceof RecordAggregate) {
@ -723,10 +723,10 @@ public final class InternalSheet {
public void removeRow(RowRecord row) { public void removeRow(RowRecord row) {
_rowsAggregate.removeRow(row); _rowsAggregate.removeRow(row);
} }
/** /**
* get the NEXT value record (from LOC). The first record that is a value record * Get all the value records (from LOC). Records will be returned from the first
* (starting at LOC) will be returned. * record (starting at LOC) which is a value record.
* *
* <P> * <P>
* This method is "loc" sensitive. Meaning you need to set LOC to where you * This method is "loc" sensitive. Meaning you need to set LOC to where you
@ -735,8 +735,27 @@ public final class InternalSheet {
* at what this sets it to. For this method, set loc to dimsloc to start with, * at what this sets it to. For this method, set loc to dimsloc to start with,
* subsequent calls will return values in (physical) sequence or NULL when you get to the end. * subsequent calls will return values in (physical) sequence or NULL when you get to the end.
* *
* @return CellValueRecordInterface representing the next value record or NULL if there are no more * @return Iterator of CellValueRecordInterface representing the value records
*/ */
public Iterator<CellValueRecordInterface> getCellValueIterator(){
return _rowsAggregate.getCellValueIterator();
}
/**
* Get all the value records (from LOC). Records will be returned from the first
* record (starting at LOC) which is a value record.
*
* <P>
* This method is "loc" sensitive. Meaning you need to set LOC to where you
* want it to start searching. If you don't know do this: setLoc(getDimsLoc).
* When adding several rows you can just start at the last one by leaving loc
* at what this sets it to. For this method, set loc to dimsloc to start with,
* subsequent calls will return values in (physical) sequence or NULL when you get to the end.
*
* @return Array of CellValueRecordInterface representing the remaining value records
* @deprecated use {@link #getValueIterator()} instead
*/
@Deprecated
public CellValueRecordInterface[] getValueRecords() { public CellValueRecordInterface[] getValueRecords() {
return _rowsAggregate.getValueRecords(); return _rowsAggregate.getValueRecords();
} }

View File

@ -27,7 +27,7 @@ import org.apache.poi.hssf.record.Record;
*/ */
public final class RecordStream { public final class RecordStream {
private final List _list; private final List<Record> _list;
private int _nextIndex; private int _nextIndex;
private int _countRead; private int _countRead;
private final int _endIx; private final int _endIx;
@ -35,14 +35,14 @@ public final class RecordStream {
/** /**
* Creates a RecordStream bounded by startIndex and endIndex * Creates a RecordStream bounded by startIndex and endIndex
*/ */
public RecordStream(List inputList, int startIndex, int endIx) { public RecordStream(List<Record> inputList, int startIndex, int endIx) {
_list = inputList; _list = inputList;
_nextIndex = startIndex; _nextIndex = startIndex;
_endIx = endIx; _endIx = endIx;
_countRead = 0; _countRead = 0;
} }
public RecordStream(List records, int startIx) { public RecordStream(List<Record> records, int startIx) {
this(records, startIx, records.size()); this(records, startIx, records.size());
} }
@ -61,7 +61,7 @@ public final class RecordStream {
/** /**
* @return the {@link Class} of the next Record. <code>null</code> if this stream is exhausted. * @return the {@link Class} of the next Record. <code>null</code> if this stream is exhausted.
*/ */
public Class peekNextClass() { public Class<? extends Record> peekNextClass() {
if(!hasNext()) { if(!hasNext()) {
return null; return null;
} }

View File

@ -447,7 +447,17 @@ public final class RowRecordsAggregate extends RecordAggregate {
return startHidden; return startHidden;
} }
/**
* Returns an iterator for the cell values
*/
public Iterator<CellValueRecordInterface> getCellValueIterator() {
return _valuesAgg.iterator();
}
/**
* @deprecated use {@link #getCellValueIterator()} instead
*/
public CellValueRecordInterface[] getValueRecords() { public CellValueRecordInterface[] getValueRecords() {
return _valuesAgg.getValueRecords(); return _valuesAgg.getValueRecords();
} }

View File

@ -18,6 +18,7 @@
package org.apache.poi.hssf.record.aggregates; package org.apache.poi.hssf.record.aggregates;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import org.apache.poi.hssf.model.RecordStream; import org.apache.poi.hssf.model.RecordStream;
@ -40,7 +41,7 @@ import org.apache.poi.ss.formula.ptg.Ptg;
* @author Glen Stampoultzis (glens at apache.org) * @author Glen Stampoultzis (glens at apache.org)
* @author Jason Height (jheight at chariot dot net dot au) * @author Jason Height (jheight at chariot dot net dot au)
*/ */
public final class ValueRecordsAggregate { public final class ValueRecordsAggregate implements Iterable<CellValueRecordInterface> {
private static final int MAX_ROW_INDEX = 0XFFFF; private static final int MAX_ROW_INDEX = 0XFFFF;
private static final int INDEX_NOT_SET = -1; private static final int INDEX_NOT_SET = -1;
private int firstcell = INDEX_NOT_SET; private int firstcell = INDEX_NOT_SET;
@ -301,10 +302,67 @@ public final class ValueRecordsAggregate {
} }
} }
/**
* iterator for CellValueRecordInterface
*/
class ValueIterator implements Iterator<CellValueRecordInterface> {
int curRowIndex = 0, curColIndex = -1;
int nextRowIndex = 0, nextColIndex = -1;
public ValueIterator() {
getNextPos();
}
void getNextPos() {
if (nextRowIndex >= records.length)
return; // no next already
while (nextRowIndex < records.length) {
++nextColIndex;
if (records[nextRowIndex] == null || nextColIndex >= records[nextRowIndex].length) {
++nextRowIndex;
nextColIndex = -1;
continue;
}
if (records[nextRowIndex][nextColIndex] != null)
return; // next cell found
}
// no next found
}
public boolean hasNext() {
return nextRowIndex < records.length;
}
public CellValueRecordInterface next() {
if (!hasNext())
throw new IndexOutOfBoundsException("iterator has no next");
curRowIndex = nextRowIndex;
curColIndex = nextColIndex;
final CellValueRecordInterface ret = records[curRowIndex][curColIndex];
getNextPos();
return ret;
}
public void remove() {
records[curRowIndex][curColIndex] = null;
}
}
/** value iterator */
public Iterator<CellValueRecordInterface> iterator() {
return new ValueIterator();
}
/** /**
* Gets all the cell records contained in this aggregate. * Gets all the cell records contained in this aggregate.
* Note {@link BlankRecord}s appear separate (not in {@link MulBlankRecord}s). * Note {@link BlankRecord}s appear separate (not in {@link MulBlankRecord}s).
* @deprecated use {@link #iterator()} instead
*/ */
@Deprecated
public CellValueRecordInterface[] getValueRecords() { public CellValueRecordInterface[] getValueRecords() {
List<CellValueRecordInterface> temp = new ArrayList<CellValueRecordInterface>(); List<CellValueRecordInterface> temp = new ArrayList<CellValueRecordInterface>();

View File

@ -142,7 +142,7 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
row = sheet.getNextRow(); row = sheet.getNextRow();
} }
CellValueRecordInterface[] cvals = sheet.getValueRecords(); Iterator<CellValueRecordInterface> iter = sheet.getCellValueIterator();
long timestart = System.currentTimeMillis(); long timestart = System.currentTimeMillis();
if (log.check( POILogger.DEBUG )) if (log.check( POILogger.DEBUG ))
@ -151,8 +151,8 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet {
HSSFRow lastrow = null; HSSFRow lastrow = null;
// Add every cell to its row // Add every cell to its row
for (int i = 0; i < cvals.length; i++) { while (iter.hasNext()) {
CellValueRecordInterface cval = cvals[i]; CellValueRecordInterface cval = iter.next();
long cellstart = System.currentTimeMillis(); long cellstart = System.currentTimeMillis();
HSSFRow hrow = lastrow; HSSFRow hrow = lastrow;