git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1879302 13f79535-47bb-0310-9956-ffa450edef68tags/before_ooxml_3rd_edition
@@ -0,0 +1,69 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xssf.streaming; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import org.apache.poi.util.Beta; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
/** | |||
* A variant of SXSSFSheet that uses IRowGenerator to create rows. | |||
* | |||
* This variant is experimental and APIs may change at short notice. | |||
* | |||
* @see EmittingSXSSFWorkbook | |||
* @since 5.0.0 | |||
*/ | |||
@Beta | |||
public class EmittingSXSSFSheet extends SXSSFSheet { | |||
private IRowGenerator rowGenerator; | |||
public EmittingSXSSFSheet(EmittingSXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException { | |||
super(workbook, xSheet, workbook.getRandomAccessWindowSize()); | |||
} | |||
@Override | |||
public InputStream getWorksheetXMLInputStream() throws IOException { | |||
throw new RuntimeException("Not supported by EmittingSXSSFSheet"); | |||
} | |||
public void setRowGenerator(IRowGenerator rowGenerator) { | |||
this.rowGenerator = rowGenerator; | |||
} | |||
public void writeRows(OutputStream out) throws IOException { | |||
// delayed creation of SheetDataWriter | |||
_writer = ((EmittingSXSSFWorkbook) _workbook).createSheetDataWriter(out); | |||
try { | |||
if (this.rowGenerator != null) { | |||
this.rowGenerator.generateRows(this); | |||
} | |||
} catch (Exception e) { | |||
throw new IOException("Error generating Excel rows", e); | |||
} finally { | |||
// flush buffered rows | |||
flushRows(0); | |||
// flush writer buffer | |||
_writer.close(); | |||
out.flush(); | |||
} | |||
} | |||
} |
@@ -0,0 +1,219 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xssf.streaming; | |||
import java.io.IOException; | |||
import java.io.OutputStream; | |||
import java.util.Iterator; | |||
import java.util.NoSuchElementException; | |||
import org.apache.poi.ss.usermodel.Sheet; | |||
import org.apache.poi.util.Beta; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
/** | |||
* An variant of SXSSFWorkbook that avoids generating a temporary file and writes data directly to | |||
* the provided OutputStream. | |||
* | |||
* This variant is experimental and APIs may change at short notice. | |||
* | |||
* @since 5.0.0 | |||
*/ | |||
@Beta | |||
public class EmittingSXSSFWorkbook extends SXSSFWorkbook { | |||
private static final POILogger logger = POILogFactory.getLogger(EmittingSXSSFWorkbook.class); | |||
public EmittingSXSSFWorkbook() { | |||
this(null); | |||
} | |||
public EmittingSXSSFWorkbook(XSSFWorkbook workbook) { | |||
this(workbook, SXSSFWorkbook.DEFAULT_WINDOW_SIZE); | |||
} | |||
public EmittingSXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize) { | |||
super(workbook, rowAccessWindowSize, false, false); | |||
} | |||
@Override | |||
protected SheetDataWriter createSheetDataWriter() throws IOException { | |||
throw new RuntimeException("Not supported by EmittingSXSSFWorkbook"); | |||
} | |||
protected StreamingSheetWriter createSheetDataWriter(OutputStream out) throws IOException { | |||
return new StreamingSheetWriter(out); | |||
} | |||
@Override | |||
protected ISheetInjector createSheetInjector(SXSSFSheet sxSheet) throws IOException { | |||
EmittingSXSSFSheet ssxSheet = (EmittingSXSSFSheet) sxSheet; | |||
return (output) -> { | |||
ssxSheet.writeRows(output); | |||
}; | |||
} | |||
@Override | |||
SXSSFSheet createAndRegisterSXSSFSheet(XSSFSheet xSheet) { | |||
final EmittingSXSSFSheet sxSheet; | |||
try { | |||
sxSheet = new EmittingSXSSFSheet(this, xSheet); | |||
} catch (IOException ioe) { | |||
throw new RuntimeException(ioe); | |||
} | |||
registerSheetMapping(sxSheet, xSheet); | |||
return sxSheet; | |||
} | |||
public EmittingSXSSFSheet createSheet() { | |||
return (EmittingSXSSFSheet) super.createSheet(); | |||
} | |||
public EmittingSXSSFSheet createSheet(String sheetname) { | |||
return (EmittingSXSSFSheet) super.createSheet(sheetname); | |||
} | |||
/** | |||
* Returns an iterator of the sheets in the workbook in sheet order. Includes hidden and very hidden sheets. | |||
* | |||
* @return an iterator of the sheets. | |||
*/ | |||
@Override | |||
public Iterator<Sheet> sheetIterator() { | |||
return new SheetIterator<Sheet>(); | |||
} | |||
private final class SheetIterator<T extends Sheet> implements Iterator<T> { | |||
final private Iterator<XSSFSheet> it; | |||
@SuppressWarnings("unchecked") | |||
public SheetIterator() { | |||
it = (Iterator<XSSFSheet>) (Iterator<? extends Sheet>) _wb.iterator(); | |||
} | |||
@Override | |||
public boolean hasNext() { | |||
return it.hasNext(); | |||
} | |||
@Override | |||
@SuppressWarnings("unchecked") | |||
public T next() throws NoSuchElementException { | |||
final XSSFSheet xssfSheet = it.next(); | |||
EmittingSXSSFSheet sxSheet = (EmittingSXSSFSheet) getSXSSFSheet(xssfSheet); | |||
return (T) (sxSheet == null ? xssfSheet : sxSheet); | |||
} | |||
/** | |||
* Unexpected behavior may occur if sheets are reordered after iterator has been created. Support for the remove | |||
* method may be added in the future if someone can figure out a reliable implementation. | |||
*/ | |||
@Override | |||
public void remove() throws IllegalStateException { | |||
throw new UnsupportedOperationException("remove method not supported on XSSFWorkbook.iterator(). " | |||
+ "Use Sheet.removeSheetAt(int) instead."); | |||
} | |||
} | |||
/** | |||
* Alias for {@link #sheetIterator()} to allow foreach loops | |||
*/ | |||
@Override | |||
public Iterator<Sheet> iterator() { | |||
return sheetIterator(); | |||
} | |||
@Override | |||
public SXSSFSheet getSheetAt(int index) { | |||
throw new RuntimeException("Not supported by EmittingSXSSFWorkbook"); | |||
} | |||
public XSSFSheet getXSSFSheetAt(int index) { | |||
return _wb.getSheetAt(index); | |||
} | |||
/** | |||
* Gets the sheet at the given index for streaming. | |||
* | |||
* @param index the index | |||
* @return the streaming sheet at | |||
*/ | |||
public EmittingSXSSFSheet getStreamingSheetAt(int index) { | |||
XSSFSheet xSheet = _wb.getSheetAt(index); | |||
SXSSFSheet sxSheet = getSXSSFSheet(xSheet); | |||
if (sxSheet == null && xSheet != null) { | |||
return (EmittingSXSSFSheet) createAndRegisterSXSSFSheet(xSheet); | |||
} else { | |||
return (EmittingSXSSFSheet) sxSheet; | |||
} | |||
} | |||
@Override | |||
public SXSSFSheet getSheet(String name) { | |||
throw new RuntimeException("Not supported by EmittingSXSSFWorkbook"); | |||
} | |||
public XSSFSheet getXSSFSheet(String name) { | |||
return _wb.getSheet(name); | |||
} | |||
/** | |||
* Gets sheet with the given name for streaming. | |||
* | |||
* @param name the name | |||
* @return the streaming sheet | |||
*/ | |||
public EmittingSXSSFSheet getStreamingSheet(String name) { | |||
XSSFSheet xSheet = _wb.getSheet(name); | |||
EmittingSXSSFSheet sxSheet = (EmittingSXSSFSheet) getSXSSFSheet(xSheet); | |||
if (sxSheet == null && xSheet != null) { | |||
return (EmittingSXSSFSheet) createAndRegisterSXSSFSheet(xSheet); | |||
} else { | |||
return sxSheet; | |||
} | |||
} | |||
/** | |||
* Removes sheet at the given index | |||
* | |||
* @param index of the sheet to remove (0-based) | |||
*/ | |||
@Override | |||
public void removeSheetAt(int index) { | |||
// Get the sheet to be removed | |||
XSSFSheet xSheet = _wb.getSheetAt(index); | |||
SXSSFSheet sxSheet = getSXSSFSheet(xSheet); | |||
// De-register it | |||
_wb.removeSheetAt(index); | |||
// The sheet may not be a streaming sheet and is not mapped | |||
if (sxSheet != null) { | |||
deregisterSheetMapping(xSheet); | |||
// Clean up temporary resources | |||
try { | |||
sxSheet.dispose(); | |||
} catch (IOException e) { | |||
logger.log(POILogger.WARN, e); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,37 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xssf.streaming; | |||
import org.apache.poi.util.Beta; | |||
/** | |||
* IRowGenerator for Emitting SXSSF sheets | |||
* | |||
* @see EmittingSXSSFWorkbook | |||
*/ | |||
@Beta | |||
public interface IRowGenerator { | |||
/** | |||
* Generate and add rows to the sheet | |||
* | |||
* @param sheet the sheet | |||
* @throws Exception the exception | |||
*/ | |||
void generateRows(SXSSFSheet sheet) throws Exception; | |||
} |
@@ -106,11 +106,13 @@ public final class SXSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator { | |||
// Process the sheets as best we can | |||
for (Sheet sheet : wb) { | |||
// Check if any rows have already been flushed out | |||
int lastFlushedRowNum = ((SXSSFSheet) sheet).getLastFlushedRowNum(); | |||
if (lastFlushedRowNum > -1) { | |||
if (! skipOutOfWindow) throw new RowFlushedException(0); | |||
logger.log(POILogger.INFO, "Rows up to " + lastFlushedRowNum + " have already been flushed, skipping"); | |||
if (sheet instanceof SXSSFSheet) { | |||
// Check if any rows have already been flushed out | |||
int lastFlushedRowNum = ((SXSSFSheet) sheet).getLastFlushedRowNum(); | |||
if (lastFlushedRowNum > -1) { | |||
if (! skipOutOfWindow) throw new RowFlushedException(0); | |||
logger.log(POILogger.INFO, "Rows up to " + lastFlushedRowNum + " have already been flushed, skipping"); | |||
} | |||
} | |||
// Evaluate what we have |
@@ -24,6 +24,7 @@ import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.ss.usermodel.Picture; | |||
import org.apache.poi.ss.usermodel.Row; | |||
import org.apache.poi.ss.usermodel.Shape; | |||
import org.apache.poi.ss.usermodel.Sheet; | |||
import org.apache.poi.ss.usermodel.Workbook; | |||
import org.apache.poi.ss.util.ImageUtils; | |||
import org.apache.poi.util.Internal; | |||
@@ -201,7 +202,8 @@ public final class SXSSFPicture implements Picture { | |||
// THE FOLLOWING THREE LINES ARE THE MAIN CHANGE compared to the non-streaming version: use the SXSSF sheet, | |||
// not the XSSF sheet (which never contais rows when using SXSSF) | |||
XSSFSheet xssfSheet = getSheet(); | |||
SXSSFSheet sheet = _wb.getSXSSFSheet(xssfSheet); | |||
SXSSFSheet sxSheet = _wb.getSXSSFSheet(xssfSheet); | |||
Sheet sheet = sxSheet == null ? xssfSheet : sxSheet; | |||
Row row = sheet.getRow(rowIndex); | |||
float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints(); | |||
return height * Units.PIXEL_DPI / Units.POINT_DPI; |
@@ -61,19 +61,26 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet; | |||
/** | |||
* Streaming version of XSSFSheet implementing the "BigGridDemo" strategy. | |||
*/ | |||
*/ | |||
public class SXSSFSheet implements Sheet | |||
{ | |||
/*package*/ final XSSFSheet _sh; | |||
private final SXSSFWorkbook _workbook; | |||
protected final SXSSFWorkbook _workbook; | |||
private final TreeMap<Integer,SXSSFRow> _rows = new TreeMap<>(); | |||
private final SheetDataWriter _writer; | |||
protected SheetDataWriter _writer; | |||
private int _randomAccessWindowSize = SXSSFWorkbook.DEFAULT_WINDOW_SIZE; | |||
private final AutoSizeColumnTracker _autoSizeColumnTracker; | |||
protected final AutoSizeColumnTracker _autoSizeColumnTracker; | |||
private int outlineLevelRow; | |||
private int lastFlushedRowNumber = -1; | |||
private boolean allFlushed; | |||
protected SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet, int randomAccessWindowSize) { | |||
_workbook = workbook; | |||
_sh = xSheet; | |||
setRandomAccessWindowSize(randomAccessWindowSize); | |||
_autoSizeColumnTracker = new AutoSizeColumnTracker(this); | |||
} | |||
public SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException { | |||
_workbook = workbook; | |||
_sh = xSheet; | |||
@@ -90,8 +97,8 @@ public class SXSSFSheet implements Sheet | |||
return _writer; | |||
} | |||
/* Gets "<sheetData>" document fragment*/ | |||
public InputStream getWorksheetXMLInputStream() throws IOException | |||
/* Gets "<sheetData>" document fragment*/ | |||
public InputStream getWorksheetXMLInputStream() throws IOException | |||
{ | |||
// flush all remaining data and close the temp file writer | |||
flushRows(0); | |||
@@ -99,7 +106,7 @@ public class SXSSFSheet implements Sheet | |||
return _writer.getWorksheetXMLInputStream(); | |||
} | |||
//start of interface implementation | |||
//start of interface implementation | |||
@Override | |||
public Iterator<Row> iterator() | |||
{ | |||
@@ -128,7 +135,7 @@ public class SXSSFSheet implements Sheet | |||
if(rownum <= _writer.getLastFlushedRow() ) { | |||
throw new IllegalArgumentException( | |||
"Attempting to write a row["+rownum+"] " + | |||
"in the range [0," + _writer.getLastFlushedRow() + "] that is already written to disk."); | |||
"in the range [0," + _writer.getLastFlushedRow() + "] that is already written to disk."); | |||
} | |||
// attempt to overwrite a existing row in the input template | |||
@@ -143,7 +150,7 @@ public class SXSSFSheet implements Sheet | |||
allFlushed = false; | |||
if(_randomAccessWindowSize >= 0 && _rows.size() > _randomAccessWindowSize) { | |||
try { | |||
flushRows(_randomAccessWindowSize); | |||
flushRows(_randomAccessWindowSize); | |||
} catch (IOException ioe) { | |||
throw new RuntimeException(ioe); | |||
} | |||
@@ -274,7 +281,7 @@ public class SXSSFSheet implements Sheet | |||
/** | |||
* Get the actual column width in pixels | |||
* | |||
* | |||
* <p> | |||
* Please note, that this method works correctly only for workbooks | |||
* with the default font size (Calibri 11pt for .xlsx). | |||
@@ -283,8 +290,8 @@ public class SXSSFSheet implements Sheet | |||
@Override | |||
public float getColumnWidthInPixels(int columnIndex) { | |||
return _sh.getColumnWidthInPixels(columnIndex); | |||
} | |||
} | |||
/** | |||
* Set the default column width for the sheet (if the columns do not define their own width) | |||
* in characters | |||
@@ -308,7 +315,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _sh.getDefaultColumnWidth(); | |||
} | |||
/** | |||
* Get the default row height for the sheet (if the rows do not define their own height) in | |||
@@ -356,7 +363,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_sh.setDefaultRowHeightInPoints(height); | |||
} | |||
/** | |||
* Returns the CellStyle that applies to the given | |||
@@ -461,7 +468,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_sh.removeMergedRegion(index); | |||
} | |||
/** | |||
* Removes a merged region of cells (hence letting them free) | |||
* | |||
@@ -568,7 +575,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _sh.isDisplayZeros(); | |||
} | |||
/** | |||
* Sets whether the worksheet is displayed from right to left instead of from left to right. | |||
* | |||
@@ -577,7 +584,7 @@ public class SXSSFSheet implements Sheet | |||
@Override | |||
public void setRightToLeft(boolean value) | |||
{ | |||
_sh.setRightToLeft(value); | |||
_sh.setRightToLeft(value); | |||
} | |||
/** | |||
@@ -588,7 +595,7 @@ public class SXSSFSheet implements Sheet | |||
@Override | |||
public boolean isRightToLeft() | |||
{ | |||
return _sh.isRightToLeft(); | |||
return _sh.isRightToLeft(); | |||
} | |||
/** | |||
@@ -733,7 +740,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_sh.setPrintGridlines(show); | |||
} | |||
/** | |||
* Returns whether row and column headings are printed. | |||
* | |||
@@ -841,7 +848,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _sh.getProtect(); | |||
} | |||
/** | |||
* Sets the protection enabled as well as the password | |||
* @param password to set for protection. Pass <code>null</code> to remove protection | |||
@@ -851,7 +858,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_sh.protectSheet(password); | |||
} | |||
/** | |||
* Answer whether scenario protection is enabled or disabled | |||
* | |||
@@ -862,7 +869,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _sh.getScenarioProtect(); | |||
} | |||
/** | |||
* Window zoom magnification for current view representing percent values. | |||
* Valid values range from 10 to 400. Horizontal and Vertical scale together. | |||
@@ -933,7 +940,7 @@ public class SXSSFSheet implements Sheet | |||
*/ | |||
@Override | |||
public void setForceFormulaRecalculation(boolean value) { | |||
_sh.setForceFormulaRecalculation(value); | |||
_sh.setForceFormulaRecalculation(value); | |||
} | |||
/** | |||
@@ -942,12 +949,12 @@ public class SXSSFSheet implements Sheet | |||
*/ | |||
@Override | |||
public boolean getForceFormulaRecalculation() { | |||
return _sh.getForceFormulaRecalculation(); | |||
return _sh.getForceFormulaRecalculation(); | |||
} | |||
/** | |||
* <i>Not implemented for SXSSFSheets</i> | |||
* | |||
* | |||
* Shifts rows between startRow and endRow n number of rows. | |||
* If you use a negative number, it will shift rows up. | |||
* Code ensures that rows don't wrap around. | |||
@@ -969,7 +976,7 @@ public class SXSSFSheet implements Sheet | |||
/** | |||
* <i>Not implemented for SXSSFSheets</i> | |||
* | |||
* | |||
* Shifts rows between startRow and endRow n number of rows. | |||
* If you use a negative number, it will shift rows up. | |||
* Code ensures that rows don't wrap around | |||
@@ -1236,7 +1243,7 @@ public class SXSSFSheet implements Sheet | |||
* Please note the rows being grouped <em>must</em> be in the current window, | |||
* if the rows are already flushed then groupRow has no effect. | |||
* </p> | |||
* | |||
* | |||
* Correct code: | |||
* <pre><code> | |||
* Workbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory | |||
@@ -1249,8 +1256,8 @@ public class SXSSFSheet implements Sheet | |||
* } | |||
* | |||
* </code></pre> | |||
* | |||
* | |||
* | |||
* | |||
* Incorrect code: | |||
* <pre><code> | |||
* Workbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory | |||
@@ -1261,7 +1268,7 @@ public class SXSSFSheet implements Sheet | |||
* sh.groupRow(100, 200); // the rows in the range [100, 200] are already flushed and groupRows has no effect | |||
* | |||
* </code></pre> | |||
* | |||
* | |||
* | |||
* @param fromRow start row (0-based) | |||
* @param toRow end row (0-based) | |||
@@ -1280,7 +1287,7 @@ public class SXSSFSheet implements Sheet | |||
setWorksheetOutlineLevelRow(); | |||
} | |||
/** | |||
* Set row groupings (like groupRow) in a stream-friendly manner | |||
* | |||
@@ -1308,8 +1315,8 @@ public class SXSSFSheet implements Sheet | |||
private void setWorksheetOutlineLevelRow() { | |||
CTWorksheet ct = _sh.getCTWorksheet(); | |||
CTSheetFormatPr pr = ct.isSetSheetFormatPr() ? | |||
ct.getSheetFormatPr() : | |||
ct.addNewSheetFormatPr(); | |||
ct.getSheetFormatPr() : | |||
ct.addNewSheetFormatPr(); | |||
if(outlineLevelRow > 0) { | |||
pr.setOutlineLevelRow((short)outlineLevelRow); | |||
} | |||
@@ -1346,7 +1353,7 @@ public class SXSSFSheet implements Sheet | |||
throw new RuntimeException("Unable to expand row: Not Implemented"); | |||
} | |||
} | |||
/** | |||
* @param rowIndex the zero based row index to collapse | |||
*/ | |||
@@ -1359,7 +1366,7 @@ public class SXSSFSheet implements Sheet | |||
// Hide all the columns until the end of the group | |||
int lastRow = writeHidden(row, startRow); | |||
SXSSFRow lastRowObj = getRow(lastRow); | |||
SXSSFRow lastRowObj = getRow(lastRow); | |||
if (lastRowObj != null) { | |||
lastRowObj.setCollapsed(true); | |||
} else { | |||
@@ -1368,7 +1375,7 @@ public class SXSSFSheet implements Sheet | |||
} | |||
} | |||
} | |||
/** | |||
* @param rowIndex the zero based row index to find from | |||
*/ | |||
@@ -1388,7 +1395,7 @@ public class SXSSFSheet implements Sheet | |||
} | |||
return currentRow + 1; | |||
} | |||
private int writeHidden(SXSSFRow xRow, int rowIndex) { | |||
int level = xRow.getOutlineLevel(); | |||
SXSSFRow currRow = getRow(rowIndex); | |||
@@ -1412,8 +1419,8 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_sh.setDefaultColumnStyle(column, style); | |||
} | |||
/** | |||
* Track a column in the sheet for auto-sizing. | |||
* Note this has undefined behavior if a column is tracked after one or more rows are written to the sheet. | |||
@@ -1428,7 +1435,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_autoSizeColumnTracker.trackColumn(column); | |||
} | |||
/** | |||
* Track several columns in the sheet for auto-sizing. | |||
* Note this has undefined behavior if columns are tracked after one or more rows are written to the sheet. | |||
@@ -1441,7 +1448,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_autoSizeColumnTracker.trackColumns(columns); | |||
} | |||
/** | |||
* Tracks all columns in the sheet for auto-sizing. If this is called, individual columns do not need to be tracked. | |||
* Because determining the best-fit width for a cell is expensive, this may affect the performance. | |||
@@ -1451,7 +1458,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_autoSizeColumnTracker.trackAllColumns(); | |||
} | |||
/** | |||
* Removes a column that was previously marked for inclusion in auto-size column tracking. | |||
* When a column is untracked, the best-fit width is forgotten. | |||
@@ -1467,7 +1474,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _autoSizeColumnTracker.untrackColumn(column); | |||
} | |||
/** | |||
* Untracks several columns in the sheet for auto-sizing. | |||
* When a column is untracked, the best-fit width is forgotten. | |||
@@ -1481,7 +1488,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _autoSizeColumnTracker.untrackColumns(columns); | |||
} | |||
/** | |||
* Untracks all columns in the sheet for auto-sizing. Best-fit column widths are forgotten. | |||
* If this is called, individual columns do not need to be untracked. | |||
@@ -1491,7 +1498,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
_autoSizeColumnTracker.untrackAllColumns(); | |||
} | |||
/** | |||
* Returns true if column is currently tracked for auto-sizing. | |||
* | |||
@@ -1503,7 +1510,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _autoSizeColumnTracker.isColumnTracked(column); | |||
} | |||
/** | |||
* Get the currently tracked columns for auto-sizing. | |||
* Note if all columns are tracked, this will only return the columns that have been explicitly or implicitly tracked, | |||
@@ -1527,7 +1534,7 @@ public class SXSSFSheet implements Sheet | |||
* </p> | |||
* You can specify whether the content of merged cells should be considered or ignored. | |||
* Default is to ignore merged cells. | |||
* | |||
* | |||
* <p> | |||
* Special note about SXSSF implementation: You must register the columns you wish to track with | |||
* the SXSSFSheet using {@link #trackColumnForAutoSizing(int)} or {@link #trackAllColumnsForAutoSizing()}. | |||
@@ -1554,7 +1561,7 @@ public class SXSSFSheet implements Sheet | |||
* </p> | |||
* You can specify whether the content of merged cells should be considered or ignored. | |||
* Default is to ignore merged cells. | |||
* | |||
* | |||
* <p> | |||
* Special note about SXSSF implementation: You must register the columns you wish to track with | |||
* the SXSSFSheet using {@link #trackColumnForAutoSizing(int)} or {@link #trackAllColumnsForAutoSizing()}. | |||
@@ -1590,21 +1597,21 @@ public class SXSSFSheet implements Sheet | |||
catch (final IllegalStateException e) { | |||
throw new IllegalStateException("Could not auto-size column. Make sure the column was tracked prior to auto-sizing the column.", e); | |||
} | |||
// get the best-fit width of rows currently in the random access window | |||
final int activeWidth = (int) (256 * SheetUtil.getColumnWidth(this, column, useMergedCells)); | |||
// the best-fit width for both flushed rows and random access window rows | |||
// flushedWidth or activeWidth may be negative if column contains only blank cells | |||
final int bestFitWidth = Math.max(flushedWidth, activeWidth); | |||
if (bestFitWidth > 0) { | |||
final int maxColumnWidth = 255*256; // The maximum column width for an individual cell is 255 characters | |||
final int width = Math.min(bestFitWidth, maxColumnWidth); | |||
setColumnWidth(column, width); | |||
} | |||
} | |||
/** | |||
* Returns cell comment for the specified row and column | |||
* | |||
@@ -1615,7 +1622,7 @@ public class SXSSFSheet implements Sheet | |||
{ | |||
return _sh.getCellComment(ref); | |||
} | |||
/** | |||
* Returns all cell comments on this sheet. | |||
* @return A map of each Comment in the sheet, keyed on the cell address where | |||
@@ -1625,7 +1632,7 @@ public class SXSSFSheet implements Sheet | |||
public Map<CellAddress, XSSFComment> getCellComments() { | |||
return _sh.getCellComments(); | |||
} | |||
/** | |||
* Get a Hyperlink in this sheet anchored at row, column | |||
* | |||
@@ -1637,7 +1644,7 @@ public class SXSSFSheet implements Sheet | |||
public XSSFHyperlink getHyperlink(int row, int column) { | |||
return _sh.getHyperlink(row, column); | |||
} | |||
/** | |||
* Get a Hyperlink in this sheet located in a cell specified by {code addr} | |||
* | |||
@@ -1649,7 +1656,7 @@ public class SXSSFSheet implements Sheet | |||
public XSSFHyperlink getHyperlink(CellAddress addr) { | |||
return _sh.getHyperlink(addr); | |||
} | |||
/** | |||
* Get a list of Hyperlinks in this sheet | |||
* | |||
@@ -1659,7 +1666,7 @@ public class SXSSFSheet implements Sheet | |||
public List<XSSFHyperlink> getHyperlinkList() { | |||
return _sh.getHyperlinkList(); | |||
} | |||
/** | |||
* {@inheritDoc} | |||
*/ | |||
@@ -1744,7 +1751,7 @@ public class SXSSFSheet implements Sheet | |||
throw new RuntimeException("Not Implemented"); | |||
} | |||
@Override | |||
public DataValidationHelper getDataValidationHelper() | |||
{ | |||
@@ -1769,7 +1776,7 @@ public class SXSSFSheet implements Sheet | |||
/** | |||
* Enable filtering for a range of cells | |||
* | |||
* | |||
* @param range the range of cells to filter | |||
*/ | |||
@Override | |||
@@ -1782,30 +1789,30 @@ public class SXSSFSheet implements Sheet | |||
public SheetConditionalFormatting getSheetConditionalFormatting(){ | |||
return _sh.getSheetConditionalFormatting(); | |||
} | |||
@Override | |||
public CellRangeAddress getRepeatingRows() { | |||
return _sh.getRepeatingRows(); | |||
return _sh.getRepeatingRows(); | |||
} | |||
@Override | |||
public CellRangeAddress getRepeatingColumns() { | |||
return _sh.getRepeatingColumns(); | |||
return _sh.getRepeatingColumns(); | |||
} | |||
@Override | |||
public void setRepeatingRows(CellRangeAddress rowRangeRef) { | |||
_sh.setRepeatingRows(rowRangeRef); | |||
_sh.setRepeatingRows(rowRangeRef); | |||
} | |||
@Override | |||
public void setRepeatingColumns(CellRangeAddress columnRangeRef) { | |||
_sh.setRepeatingColumns(columnRangeRef); | |||
_sh.setRepeatingColumns(columnRangeRef); | |||
} | |||
//end of interface implementation | |||
/** | |||
* Specifies how many rows can be accessed at most via getRow(). | |||
@@ -1821,12 +1828,12 @@ public class SXSSFSheet implements Sheet | |||
*/ | |||
public void setRandomAccessWindowSize(int value) | |||
{ | |||
if(value == 0 || value < -1) { | |||
throw new IllegalArgumentException("RandomAccessWindowSize must be either -1 or a positive integer"); | |||
} | |||
_randomAccessWindowSize = value; | |||
if(value == 0 || value < -1) { | |||
throw new IllegalArgumentException("RandomAccessWindowSize must be either -1 or a positive integer"); | |||
} | |||
_randomAccessWindowSize = value; | |||
} | |||
/** | |||
* Are all rows flushed to disk? | |||
*/ | |||
@@ -1880,7 +1887,7 @@ public class SXSSFSheet implements Sheet | |||
} | |||
public void changeRowNum(SXSSFRow row, int newRowNum) | |||
{ | |||
removeRow(row); | |||
_rows.put(newRowNum,row); | |||
} | |||
@@ -1904,7 +1911,7 @@ public class SXSSFSheet implements Sheet | |||
if (!allFlushed) { | |||
flushRows(); | |||
} | |||
return _writer.dispose(); | |||
return _writer == null || _writer.dispose(); | |||
} | |||
@Override | |||
@@ -1935,21 +1942,21 @@ public class SXSSFSheet implements Sheet | |||
public void setTabColor(XSSFColor color) { | |||
_sh.setTabColor(color); | |||
} | |||
/** | |||
* Enable sheet protection | |||
*/ | |||
public void enableLocking() { | |||
safeGetProtectionField().setSheet(true); | |||
} | |||
/** | |||
* Disable sheet protection | |||
*/ | |||
public void disableLocking() { | |||
safeGetProtectionField().setSheet(false); | |||
} | |||
/** | |||
* Enable or disable Autofilters locking. | |||
* This does not modify sheet protection status. | |||
@@ -1958,7 +1965,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockAutoFilter(boolean enabled) { | |||
safeGetProtectionField().setAutoFilter(enabled); | |||
} | |||
/** | |||
* Enable or disable Deleting columns locking. | |||
* This does not modify sheet protection status. | |||
@@ -1967,7 +1974,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockDeleteColumns(boolean enabled) { | |||
safeGetProtectionField().setDeleteColumns(enabled); | |||
} | |||
/** | |||
* Enable or disable Deleting rows locking. | |||
* This does not modify sheet protection status. | |||
@@ -1976,7 +1983,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockDeleteRows(boolean enabled) { | |||
safeGetProtectionField().setDeleteRows(enabled); | |||
} | |||
/** | |||
* Enable or disable Formatting cells locking. | |||
* This does not modify sheet protection status. | |||
@@ -1985,7 +1992,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockFormatCells(boolean enabled) { | |||
safeGetProtectionField().setFormatCells(enabled); | |||
} | |||
/** | |||
* Enable or disable Formatting columns locking. | |||
* This does not modify sheet protection status. | |||
@@ -1994,7 +2001,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockFormatColumns(boolean enabled) { | |||
safeGetProtectionField().setFormatColumns(enabled); | |||
} | |||
/** | |||
* Enable or disable Formatting rows locking. | |||
* This does not modify sheet protection status. | |||
@@ -2003,7 +2010,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockFormatRows(boolean enabled) { | |||
safeGetProtectionField().setFormatRows(enabled); | |||
} | |||
/** | |||
* Enable or disable Inserting columns locking. | |||
* This does not modify sheet protection status. | |||
@@ -2012,7 +2019,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockInsertColumns(boolean enabled) { | |||
safeGetProtectionField().setInsertColumns(enabled); | |||
} | |||
/** | |||
* Enable or disable Inserting hyperlinks locking. | |||
* This does not modify sheet protection status. | |||
@@ -2021,7 +2028,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockInsertHyperlinks(boolean enabled) { | |||
safeGetProtectionField().setInsertHyperlinks(enabled); | |||
} | |||
/** | |||
* Enable or disable Inserting rows locking. | |||
* This does not modify sheet protection status. | |||
@@ -2030,7 +2037,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockInsertRows(boolean enabled) { | |||
safeGetProtectionField().setInsertRows(enabled); | |||
} | |||
/** | |||
* Enable or disable Pivot Tables locking. | |||
* This does not modify sheet protection status. | |||
@@ -2039,7 +2046,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockPivotTables(boolean enabled) { | |||
safeGetProtectionField().setPivotTables(enabled); | |||
} | |||
/** | |||
* Enable or disable Sort locking. | |||
* This does not modify sheet protection status. | |||
@@ -2048,7 +2055,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockSort(boolean enabled) { | |||
safeGetProtectionField().setSort(enabled); | |||
} | |||
/** | |||
* Enable or disable Objects locking. | |||
* This does not modify sheet protection status. | |||
@@ -2057,7 +2064,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockObjects(boolean enabled) { | |||
safeGetProtectionField().setObjects(enabled); | |||
} | |||
/** | |||
* Enable or disable Scenarios locking. | |||
* This does not modify sheet protection status. | |||
@@ -2066,7 +2073,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockScenarios(boolean enabled) { | |||
safeGetProtectionField().setScenarios(enabled); | |||
} | |||
/** | |||
* Enable or disable Selection of locked cells locking. | |||
* This does not modify sheet protection status. | |||
@@ -2075,7 +2082,7 @@ public class SXSSFSheet implements Sheet | |||
public void lockSelectLockedCells(boolean enabled) { | |||
safeGetProtectionField().setSelectLockedCells(enabled); | |||
} | |||
/** | |||
* Enable or disable Selection of unlocked cells locking. | |||
* This does not modify sheet protection status. | |||
@@ -2085,7 +2092,7 @@ public class SXSSFSheet implements Sheet | |||
safeGetProtectionField().setSelectUnlockedCells(enabled); | |||
} | |||
private CTSheetProtection safeGetProtectionField() { | |||
CTWorksheet ct = _sh.getCTWorksheet(); | |||
if (!isSheetProtectionEnabled()) { | |||
@@ -2093,12 +2100,12 @@ public class SXSSFSheet implements Sheet | |||
} | |||
return ct.getSheetProtection(); | |||
} | |||
/* package */ boolean isSheetProtectionEnabled() { | |||
CTWorksheet ct = _sh.getCTWorksheet(); | |||
return (ct.isSetSheetProtection()); | |||
} | |||
/** | |||
* Set background color of the sheet tab | |||
* | |||
@@ -2112,10 +2119,10 @@ public class SXSSFSheet implements Sheet | |||
color.setIndexed(colorIndex); | |||
pr.setTabColor(color); | |||
} | |||
@NotImplemented | |||
@Override | |||
public void shiftColumns(int startColumn, int endColumn, int n){ | |||
throw new UnsupportedOperationException("Not Implemented"); | |||
@NotImplemented | |||
@Override | |||
public void shiftColumns(int startColumn, int endColumn, int n){ | |||
throw new UnsupportedOperationException("Not Implemented"); | |||
} | |||
} |
@@ -96,13 +96,17 @@ public class SXSSFWorkbook implements Workbook { | |||
public static final int DEFAULT_WINDOW_SIZE = 100; | |||
private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbook.class); | |||
private final XSSFWorkbook _wb; | |||
protected final XSSFWorkbook _wb; | |||
private final Map<SXSSFSheet,XSSFSheet> _sxFromXHash = new HashMap<>(); | |||
private final Map<XSSFSheet,SXSSFSheet> _xFromSxHash = new HashMap<>(); | |||
private int _randomAccessWindowSize = DEFAULT_WINDOW_SIZE; | |||
protected static interface ISheetInjector { | |||
void writeSheetData(OutputStream out) throws IOException; | |||
} | |||
/** | |||
* whether temp files should be compressed. | |||
*/ | |||
@@ -111,23 +115,23 @@ public class SXSSFWorkbook implements Workbook { | |||
/** | |||
* shared string table - a cache of strings in this workbook | |||
*/ | |||
private final SharedStringsTable _sharedStringSource; | |||
protected final SharedStringsTable _sharedStringSource; | |||
/** | |||
* controls whether Zip64 mode is used - Always became the default in POI 5.0.0 | |||
*/ | |||
private Zip64Mode zip64Mode = Zip64Mode.Always; | |||
protected Zip64Mode zip64Mode = Zip64Mode.Always; | |||
/** | |||
* Construct a new workbook with default row window size | |||
*/ | |||
public SXSSFWorkbook(){ | |||
this(null /*workbook*/); | |||
this(null /*workbook*/); | |||
} | |||
/** | |||
* <p>Construct a workbook from a template.</p> | |||
* | |||
* | |||
* There are three use-cases to use SXSSFWorkbook(XSSFWorkbook) : | |||
* <ol> | |||
* <li> | |||
@@ -144,7 +148,7 @@ public class SXSSFWorkbook implements Workbook { | |||
* </li> | |||
* </ol> | |||
* All three use cases can work in a combination. | |||
* | |||
* | |||
* What is not supported: | |||
* <ul> | |||
* <li> | |||
@@ -161,9 +165,9 @@ public class SXSSFWorkbook implements Workbook { | |||
* @param workbook the template workbook | |||
*/ | |||
public SXSSFWorkbook(XSSFWorkbook workbook){ | |||
this(workbook, DEFAULT_WINDOW_SIZE); | |||
this(workbook, DEFAULT_WINDOW_SIZE); | |||
} | |||
/** | |||
* Constructs an workbook from an existing workbook. | |||
@@ -186,7 +190,7 @@ public class SXSSFWorkbook implements Workbook { | |||
* @param rowAccessWindowSize the number of rows that are kept in memory until flushed out, see above. | |||
*/ | |||
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize){ | |||
this(workbook,rowAccessWindowSize, false); | |||
this(workbook,rowAccessWindowSize, false); | |||
} | |||
/** | |||
@@ -210,8 +214,8 @@ public class SXSSFWorkbook implements Workbook { | |||
* @param rowAccessWindowSize the number of rows that are kept in memory until flushed out, see above. | |||
* @param compressTmpFiles whether to use gzip compression for temporary files | |||
*/ | |||
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles){ | |||
this(workbook,rowAccessWindowSize, compressTmpFiles, false); | |||
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles) { | |||
this(workbook,rowAccessWindowSize, compressTmpFiles, false); | |||
} | |||
/** | |||
@@ -237,11 +241,11 @@ public class SXSSFWorkbook implements Workbook { | |||
* @param compressTmpFiles whether to use gzip compression for temporary files | |||
* @param useSharedStringsTable whether to use a shared strings table | |||
*/ | |||
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable){ | |||
public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable) { | |||
setRandomAccessWindowSize(rowAccessWindowSize); | |||
setCompressTempFiles(compressTmpFiles); | |||
if (workbook == null) { | |||
_wb=new XSSFWorkbook(); | |||
_wb = new XSSFWorkbook(); | |||
_sharedStringSource = useSharedStringsTable ? _wb.getSharedStringSource() : null; | |||
} else { | |||
_wb=workbook; | |||
@@ -273,7 +277,7 @@ public class SXSSFWorkbook implements Workbook { | |||
* @param rowAccessWindowSize the number of rows that are kept in memory until flushed out, see above. | |||
*/ | |||
public SXSSFWorkbook(int rowAccessWindowSize){ | |||
this(null /*workbook*/, rowAccessWindowSize); | |||
this(null /*workbook*/, rowAccessWindowSize); | |||
} | |||
/** | |||
@@ -282,10 +286,10 @@ public class SXSSFWorkbook implements Workbook { | |||
* @return The number of rows that are kept in memory at once before flushing them out. | |||
*/ | |||
public int getRandomAccessWindowSize() { | |||
return _randomAccessWindowSize; | |||
return _randomAccessWindowSize; | |||
} | |||
private void setRandomAccessWindowSize(int rowAccessWindowSize) { | |||
protected void setRandomAccessWindowSize(int rowAccessWindowSize) { | |||
if(rowAccessWindowSize == 0 || rowAccessWindowSize < -1) { | |||
throw new IllegalArgumentException("rowAccessWindowSize must be greater than 0 or -1"); | |||
} | |||
@@ -323,7 +327,7 @@ public class SXSSFWorkbook implements Workbook { | |||
* Please note the the "compress" option may cause performance penalty. | |||
* </p> | |||
* <p> | |||
* Setting this option only affects compression for subsequent <code>createSheet()</code> | |||
* Setting this option only affects compression for subsequent <code>createSheet()</code> | |||
* calls. | |||
* </p> | |||
* @param compress whether to compress temp files | |||
@@ -331,7 +335,7 @@ public class SXSSFWorkbook implements Workbook { | |||
public void setCompressTempFiles(boolean compress) { | |||
_compressTmpFiles = compress; | |||
} | |||
@Internal | |||
protected SharedStringsTable getSharedStringSource() { | |||
return _sharedStringSource; | |||
@@ -341,7 +345,7 @@ public class SXSSFWorkbook implements Workbook { | |||
if(_compressTmpFiles) { | |||
return new GZIPSheetDataWriter(_sharedStringSource); | |||
} | |||
return new SheetDataWriter(_sharedStringSource); | |||
} | |||
@@ -364,20 +368,20 @@ public class SXSSFWorkbook implements Workbook { | |||
void deregisterSheetMapping(XSSFSheet xSheet) | |||
{ | |||
SXSSFSheet sxSheet=getSXSSFSheet(xSheet); | |||
// ensure that the writer is closed in all cases to not have lingering writers | |||
try { | |||
sxSheet.getSheetDataWriter().close(); | |||
} catch (IOException e) { | |||
// ignore exception here | |||
} | |||
_sxFromXHash.remove(sxSheet); | |||
_xFromSxHash.remove(xSheet); | |||
} | |||
private XSSFSheet getSheetFromZipEntryName(String sheetRef) | |||
protected XSSFSheet getSheetFromZipEntryName(String sheetRef) | |||
{ | |||
for(XSSFSheet sheet : _sxFromXHash.values()) | |||
{ | |||
@@ -408,9 +412,7 @@ public class SXSSFWorkbook implements Workbook { | |||
// See bug 56557, we should not inject data into the special ChartSheets | |||
if (xSheet != null && !(xSheet instanceof XSSFChartSheet)) { | |||
SXSSFSheet sxSheet = getSXSSFSheet(xSheet); | |||
try (InputStream xis = sxSheet.getWorksheetXMLInputStream()) { | |||
copyStreamAndInjectWorksheet(is, zos, xis); | |||
} | |||
copyStreamAndInjectWorksheet(is, zos, createSheetInjector(sxSheet)); | |||
} else { | |||
IOUtils.copy(is, zos); | |||
} | |||
@@ -434,7 +436,17 @@ public class SXSSFWorkbook implements Workbook { | |||
} | |||
} | |||
private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out, InputStream worksheetData) throws IOException { | |||
protected ISheetInjector createSheetInjector(SXSSFSheet sxSheet) throws IOException { | |||
return (output) -> { | |||
try (InputStream xis = sxSheet.getWorksheetXMLInputStream()) { | |||
// Copy the worksheet data to "output". | |||
IOUtils.copy(xis, output); | |||
} | |||
}; | |||
} | |||
// private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out, InputStream worksheetData) throws IOException { | |||
private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out, ISheetInjector sheetInjector) throws IOException { | |||
InputStreamReader inReader = new InputStreamReader(in, StandardCharsets.UTF_8); | |||
OutputStreamWriter outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8); | |||
boolean needsStartTag = true; | |||
@@ -450,58 +462,58 @@ public class SXSSFWorkbook implements Workbook { | |||
pos++; | |||
if(pos==n) | |||
{ | |||
if ("<sheetData".equals(s)) | |||
{ | |||
c = inReader.read(); | |||
if (c == -1) | |||
{ | |||
outWriter.write(s); | |||
break; | |||
} | |||
if (c == '>') | |||
{ | |||
// Found <sheetData> | |||
outWriter.write(s); | |||
outWriter.write(c); | |||
s = "</sheetData>"; | |||
n = s.length(); | |||
pos = 0; | |||
needsStartTag = false; | |||
continue; | |||
} | |||
if (c == '/') | |||
{ | |||
// Found <sheetData/ | |||
c = inReader.read(); | |||
if (c == -1) | |||
{ | |||
outWriter.write(s); | |||
break; | |||
} | |||
if (c == '>') | |||
{ | |||
// Found <sheetData/> | |||
break; | |||
} | |||
outWriter.write(s); | |||
outWriter.write('/'); | |||
outWriter.write(c); | |||
pos = 0; | |||
continue; | |||
} | |||
outWriter.write(s); | |||
outWriter.write('/'); | |||
outWriter.write(c); | |||
pos = 0; | |||
continue; | |||
} | |||
else | |||
{ | |||
// Found </sheetData> | |||
break; | |||
} | |||
if ("<sheetData".equals(s)) | |||
{ | |||
c = inReader.read(); | |||
if (c == -1) | |||
{ | |||
outWriter.write(s); | |||
break; | |||
} | |||
if (c == '>') | |||
{ | |||
// Found <sheetData> | |||
outWriter.write(s); | |||
outWriter.write(c); | |||
s = "</sheetData>"; | |||
n = s.length(); | |||
pos = 0; | |||
needsStartTag = false; | |||
continue; | |||
} | |||
if (c == '/') | |||
{ | |||
// Found <sheetData/ | |||
c = inReader.read(); | |||
if (c == -1) | |||
{ | |||
outWriter.write(s); | |||
break; | |||
} | |||
if (c == '>') | |||
{ | |||
// Found <sheetData/> | |||
break; | |||
} | |||
outWriter.write(s); | |||
outWriter.write('/'); | |||
outWriter.write(c); | |||
pos = 0; | |||
continue; | |||
} | |||
outWriter.write(s); | |||
outWriter.write('/'); | |||
outWriter.write(c); | |||
pos = 0; | |||
continue; | |||
} | |||
else | |||
{ | |||
// Found </sheetData> | |||
break; | |||
} | |||
} | |||
} | |||
else | |||
@@ -523,11 +535,10 @@ public class SXSSFWorkbook implements Workbook { | |||
outWriter.flush(); | |||
if (needsStartTag) | |||
{ | |||
outWriter.write("<sheetData>\n"); | |||
outWriter.flush(); | |||
outWriter.write("<sheetData>\n"); | |||
outWriter.flush(); | |||
} | |||
//Copy the worksheet data to "out". | |||
IOUtils.copy(worksheetData,out); | |||
sheetInjector.writeSheetData(out); | |||
outWriter.write("</sheetData>"); | |||
outWriter.flush(); | |||
//Copy the rest of "in" to "out". | |||
@@ -732,7 +743,7 @@ public class SXSSFWorkbook implements Workbook { | |||
{ | |||
return _wb.getNumberOfSheets(); | |||
} | |||
/** | |||
* Returns an iterator of the sheets in the workbook | |||
* in sheet order. Includes hidden and very hidden sheets. | |||
@@ -743,7 +754,7 @@ public class SXSSFWorkbook implements Workbook { | |||
public Iterator<Sheet> sheetIterator() { | |||
return new SheetIterator<>(); | |||
} | |||
private final class SheetIterator<T extends Sheet> implements Iterator<T> { | |||
final private Iterator<XSSFSheet> it; | |||
@SuppressWarnings("unchecked") | |||
@@ -771,7 +782,7 @@ public class SXSSFWorkbook implements Workbook { | |||
"Use Sheet.removeSheetAt(int) instead."); | |||
} | |||
} | |||
/** | |||
* Alias for {@link #sheetIterator()} to allow | |||
* foreach loops | |||
@@ -816,11 +827,11 @@ public class SXSSFWorkbook implements Workbook { | |||
// Get the sheet to be removed | |||
XSSFSheet xSheet = _wb.getSheetAt(index); | |||
SXSSFSheet sxSheet = getSXSSFSheet(xSheet); | |||
// De-register it | |||
_wb.removeSheetAt(index); | |||
deregisterSheetMapping(xSheet); | |||
// Clean up temporary resources | |||
try { | |||
sxSheet.dispose(); | |||
@@ -839,7 +850,7 @@ public class SXSSFWorkbook implements Workbook { | |||
{ | |||
return _wb.createFont(); | |||
} | |||
/** | |||
* Finds a font that matches the one with the supplied attributes | |||
* | |||
@@ -905,7 +916,7 @@ public class SXSSFWorkbook implements Workbook { | |||
} | |||
/** | |||
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage} | |||
* Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage} | |||
* on which this Workbook is based, if any. | |||
* | |||
* <p>Once this has been called, no further | |||
@@ -918,20 +929,21 @@ public class SXSSFWorkbook implements Workbook { | |||
for (SXSSFSheet sheet : _xFromSxHash.values()) | |||
{ | |||
try { | |||
sheet.getSheetDataWriter().close(); | |||
SheetDataWriter _writer = sheet.getSheetDataWriter(); | |||
if (_writer != null) _writer.close(); | |||
} catch (IOException e) { | |||
logger.log(POILogger.WARN, | |||
"An exception occurred while closing sheet data writer for sheet " | |||
+ sheet.getSheetName() + ".", e); | |||
+ sheet.getSheetName() + ".", e); | |||
} | |||
} | |||
// Tell the base workbook to close, does nothing if | |||
// Tell the base workbook to close, does nothing if | |||
// it's a newly created one | |||
_wb.close(); | |||
} | |||
/** | |||
* Write out this workbook to an OutputStream. | |||
* | |||
@@ -962,14 +974,14 @@ public class SXSSFWorkbook implements Workbook { | |||
throw new IOException("Could not delete temporary file after processing: " + tmplFile); | |||
} | |||
} | |||
protected void flushSheets() throws IOException { | |||
for (SXSSFSheet sheet : _xFromSxHash.values()) | |||
{ | |||
sheet.flushRows(); | |||
} | |||
} | |||
/** | |||
* Dispose of temporary files backing this workbook on disk. | |||
* Calling this method will render the workbook unusable. | |||
@@ -1053,7 +1065,7 @@ public class SXSSFWorkbook implements Workbook { | |||
_wb.removeName(name); | |||
} | |||
/** | |||
/** | |||
* Sets the printarea for the sheet provided | |||
* <p> | |||
* i.e. Reference = $A$1:$B$2 | |||
@@ -1188,7 +1200,7 @@ public class SXSSFWorkbook implements Workbook { | |||
protected boolean isDate1904() { | |||
return _wb.isDate1904(); | |||
} | |||
@Override | |||
@NotImplemented("XSSFWorkbook#isHidden is not implemented") | |||
public boolean isHidden() | |||
@@ -1214,7 +1226,7 @@ public class SXSSFWorkbook implements Workbook { | |||
{ | |||
return _wb.isSheetVeryHidden(sheetIx); | |||
} | |||
@Override | |||
public SheetVisibility getSheetVisibility(int sheetIx) { | |||
return _wb.getSheetVisibility(sheetIx); | |||
@@ -1230,13 +1242,13 @@ public class SXSSFWorkbook implements Workbook { | |||
public void setSheetVisibility(int sheetIx, SheetVisibility visibility) { | |||
_wb.setSheetVisibility(sheetIx, visibility); | |||
} | |||
/** | |||
* <i>Not implemented for SXSSFWorkbook</i> | |||
* | |||
* Adds the LinkTable records required to allow formulas referencing | |||
* the specified external workbook to be added to this one. Allows | |||
* formulas such as "[MyOtherWorkbook]Sheet3!$A$5" to be added to the | |||
* formulas such as "[MyOtherWorkbook]Sheet3!$A$5" to be added to the | |||
* file, for workbooks not already referenced. | |||
* | |||
* Note: this is not implemented and thus currently throws an Exception stating this. | |||
@@ -1251,7 +1263,7 @@ public class SXSSFWorkbook implements Workbook { | |||
public int linkExternalWorkbook(String name, Workbook workbook) { | |||
throw new RuntimeException("Not Implemented"); | |||
} | |||
/** | |||
* Register a new toolpack in this workbook. | |||
* | |||
@@ -1290,7 +1302,7 @@ public class SXSSFWorkbook implements Workbook { | |||
/** | |||
* Returns the spreadsheet version (EXCLE2007) of this workbook | |||
* | |||
* | |||
* @return EXCEL2007 SpreadsheetVersion enum | |||
* @since 3.14 beta 2 | |||
*/ | |||
@@ -1303,6 +1315,6 @@ public class SXSSFWorkbook implements Workbook { | |||
public int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException { | |||
return _wb.addOlePackage(oleData, label, fileName, command); | |||
} | |||
//end of interface implementation | |||
} |
@@ -55,7 +55,7 @@ public class SheetDataWriter implements Closeable { | |||
private static final POILogger logger = POILogFactory.getLogger(SheetDataWriter.class); | |||
private final File _fd; | |||
private final Writer _out; | |||
protected final Writer _out; | |||
private int _rownum; | |||
private int _numberOfFlushedRows; | |||
private int _lowestIndexOfFlushedRows; // meaningful only of _numberOfFlushedRows>0 | |||
@@ -72,6 +72,11 @@ public class SheetDataWriter implements Closeable { | |||
_fd = createTempFile(); | |||
_out = createWriter(_fd); | |||
} | |||
public SheetDataWriter(Writer writer) throws IOException { | |||
_fd = null; | |||
_out = writer; | |||
} | |||
public SheetDataWriter(SharedStringsTable sharedStringsTable) throws IOException { | |||
this(); |
@@ -0,0 +1,84 @@ | |||
/* ==================================================================== | |||
Licensed to the Apache Software Foundation (ASF) under one or more | |||
contributor license agreements. See the NOTICE file distributed with | |||
this work for additional information regarding copyright ownership. | |||
The ASF licenses this file to You under the Apache License, Version 2.0 | |||
(the "License"); you may not use this file except in compliance with | |||
the License. You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
==================================================================== */ | |||
package org.apache.poi.xssf.streaming; | |||
import java.io.BufferedWriter; | |||
import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.io.OutputStreamWriter; | |||
import java.io.Writer; | |||
import org.apache.poi.util.Beta; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
/** | |||
* Unlike SheetDataWriter, this writer does not create a temporary file, it writes data directly | |||
* to the provided OutputStream. | |||
* @since 5.0.0 | |||
*/ | |||
@Beta | |||
public class StreamingSheetWriter extends SheetDataWriter { | |||
private static final POILogger logger = POILogFactory.getLogger(StreamingSheetWriter.class); | |||
public StreamingSheetWriter() throws IOException { | |||
throw new RuntimeException("StreamingSheetWriter requires OutputStream"); | |||
} | |||
public StreamingSheetWriter(OutputStream out) throws IOException { | |||
super(createWriter(out)); | |||
logger.log(POILogger.DEBUG, "Preparing SSXSSF sheet writer"); | |||
} | |||
@Override | |||
public File createTempFile() throws IOException { | |||
throw new RuntimeException("Not supported with StreamingSheetWriter"); | |||
} | |||
@Override | |||
public Writer createWriter(File fd) throws IOException { | |||
throw new RuntimeException("Not supported with StreamingSheetWriter"); | |||
} | |||
/** | |||
* Create a writer for the sheet data. | |||
* | |||
* @param out the output stream to write to | |||
*/ | |||
protected static Writer createWriter(OutputStream out) throws IOException { | |||
return new BufferedWriter(new OutputStreamWriter(out, "UTF-8")); | |||
} | |||
@Override | |||
public void close() throws IOException { | |||
_out.flush(); | |||
} | |||
@Override | |||
public InputStream getWorksheetXMLInputStream() throws IOException { | |||
throw new RuntimeException("Not supported with StreamingSheetWriter"); | |||
} | |||
@Override | |||
boolean dispose() throws IOException { | |||
_out.close(); | |||
return true; | |||
} | |||
} |
@@ -0,0 +1,488 @@ | |||
/* | |||
* ==================================================================== | |||
* Licensed to the Apache Software Foundation (ASF) under one or more | |||
* contributor license agreements. See the NOTICE file distributed with | |||
* this work for additional information regarding copyright ownership. | |||
* The ASF licenses this file to You under the Apache License, Version 2.0 | |||
* (the "License"); you may not use this file except in compliance with | |||
* the License. You may obtain a copy of the License at | |||
* | |||
* http://www.apache.org/licenses/LICENSE-2.0 | |||
* | |||
* Unless required by applicable law or agreed to in writing, software | |||
* distributed under the License is distributed on an "AS IS" BASIS, | |||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
* See the License for the specific language governing permissions and | |||
* limitations under the License. | |||
* ==================================================================== | |||
*/ | |||
package org.apache.poi.xssf.streaming; | |||
import static org.junit.Assert.assertEquals; | |||
import static org.junit.Assert.assertNotNull; | |||
import static org.junit.Assert.assertNull; | |||
import static org.junit.Assert.assertSame; | |||
import static org.junit.Assert.assertTrue; | |||
import static org.junit.Assert.fail; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.ByteArrayOutputStream; | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.FileOutputStream; | |||
import java.io.IOException; | |||
import java.util.Arrays; | |||
import org.apache.poi.POIDataSamples; | |||
import org.apache.poi.openxml4j.opc.OPCPackage; | |||
import org.apache.poi.openxml4j.opc.PackageAccess; | |||
import org.apache.poi.ss.usermodel.BaseTestXWorkbook; | |||
import org.apache.poi.ss.usermodel.Cell; | |||
import org.apache.poi.ss.usermodel.CellType; | |||
import org.apache.poi.ss.usermodel.Row; | |||
import org.apache.poi.ss.usermodel.Sheet; | |||
import org.apache.poi.ss.usermodel.Workbook; | |||
import org.apache.poi.ss.usermodel.WorkbookFactory; | |||
import org.apache.poi.ss.util.CellReference; | |||
import org.apache.poi.util.NullOutputStream; | |||
import org.apache.poi.xssf.SXSSFITestDataProvider; | |||
import org.apache.poi.xssf.XSSFTestDataSamples; | |||
import org.apache.poi.xssf.usermodel.XSSFCell; | |||
import org.apache.poi.xssf.usermodel.XSSFRow; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import org.junit.After; | |||
import org.junit.Ignore; | |||
import org.junit.Test; | |||
public final class TestEmittingSXSSFWorkbook extends BaseTestXWorkbook { | |||
public TestEmittingSXSSFWorkbook() { | |||
super(SXSSFITestDataProvider.instance); | |||
} | |||
@After | |||
public void tearDown() { | |||
((SXSSFITestDataProvider) _testDataProvider).cleanup(); | |||
} | |||
/** | |||
* cloning of sheets is not supported in SXSSF | |||
*/ | |||
@Override | |||
@Test | |||
public void cloneSheet() throws IOException { | |||
try { | |||
super.cloneSheet(); | |||
fail("expected exception"); | |||
} catch (RuntimeException e) { | |||
assertEquals("Not Implemented", e.getMessage()); | |||
} | |||
} | |||
/** | |||
* cloning of sheets is not supported in SXSSF | |||
*/ | |||
@Override | |||
@Test | |||
public void sheetClone() throws IOException { | |||
try { | |||
super.sheetClone(); | |||
fail("expected exception"); | |||
} catch (RuntimeException e) { | |||
assertEquals("Not Implemented", e.getMessage()); | |||
} | |||
} | |||
/** | |||
* Skip this test, as SXSSF doesn't update formulas on sheet name changes. | |||
*/ | |||
@Override | |||
@Ignore("SXSSF doesn't update formulas on sheet name changes, as most cells probably aren't in memory at the time") | |||
@Test | |||
public void setSheetName() { | |||
} | |||
@Test | |||
public void existingWorkbook() throws IOException { | |||
XSSFWorkbook xssfWb1 = new XSSFWorkbook(); | |||
xssfWb1.createSheet("S1"); | |||
EmittingSXSSFWorkbook wb1 = new EmittingSXSSFWorkbook(xssfWb1); | |||
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1); | |||
assertTrue(wb1.dispose()); | |||
EmittingSXSSFWorkbook wb2 = new EmittingSXSSFWorkbook(xssfWb2); | |||
assertEquals(1, wb2.getNumberOfSheets()); | |||
Sheet sheet = wb2.getStreamingSheetAt(0); | |||
assertNotNull(sheet); | |||
assertEquals("S1", sheet.getSheetName()); | |||
assertTrue(wb2.dispose()); | |||
xssfWb2.close(); | |||
xssfWb1.close(); | |||
wb2.close(); | |||
wb1.close(); | |||
} | |||
@Test | |||
public void useSharedStringsTable() throws Exception { | |||
// not supported with EmittingSXSSF | |||
} | |||
@Test | |||
public void addToExistingWorkbook() throws IOException { | |||
XSSFWorkbook xssfWb1 = new XSSFWorkbook(); | |||
xssfWb1.createSheet("S1"); | |||
Sheet sheet = xssfWb1.createSheet("S2"); | |||
Row row = sheet.createRow(1); | |||
Cell cell = row.createCell(1); | |||
cell.setCellValue("value 2_1_1"); | |||
EmittingSXSSFWorkbook wb1 = new EmittingSXSSFWorkbook(xssfWb1); | |||
XSSFWorkbook xssfWb2 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb1); | |||
assertTrue(wb1.dispose()); | |||
xssfWb1.close(); | |||
EmittingSXSSFWorkbook wb2 = new EmittingSXSSFWorkbook(xssfWb2); | |||
// Add a row to the existing empty sheet | |||
EmittingSXSSFSheet ssheet1 = wb2.getStreamingSheetAt(0); | |||
ssheet1.setRowGenerator((ssxSheet) -> { | |||
Row row1_1 = ssxSheet.createRow(1); | |||
Cell cell1_1_1 = row1_1.createCell(1); | |||
cell1_1_1.setCellValue("value 1_1_1"); | |||
}); | |||
// Add a row to the existing non-empty sheet | |||
EmittingSXSSFSheet ssheet2 = wb2.getStreamingSheetAt(1); | |||
ssheet2.setRowGenerator((ssxSheet) -> { | |||
Row row2_2 = ssxSheet.createRow(2); | |||
Cell cell2_2_1 = row2_2.createCell(1); | |||
cell2_2_1.setCellValue("value 2_2_1"); | |||
}); | |||
// Add a sheet with one row | |||
EmittingSXSSFSheet ssheet3 = wb2.createSheet("S3"); | |||
ssheet3.setRowGenerator((ssxSheet) -> { | |||
Row row3_1 = ssxSheet.createRow(1); | |||
Cell cell3_1_1 = row3_1.createCell(1); | |||
cell3_1_1.setCellValue("value 3_1_1"); | |||
}); | |||
XSSFWorkbook xssfWb3 = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb2); | |||
wb2.close(); | |||
assertEquals(3, xssfWb3.getNumberOfSheets()); | |||
// Verify sheet 1 | |||
XSSFSheet sheet1 = xssfWb3.getSheetAt(0); | |||
assertEquals("S1", sheet1.getSheetName()); | |||
assertEquals(1, sheet1.getPhysicalNumberOfRows()); | |||
XSSFRow row1_1 = sheet1.getRow(1); | |||
assertNotNull(row1_1); | |||
XSSFCell cell1_1_1 = row1_1.getCell(1); | |||
assertNotNull(cell1_1_1); | |||
assertEquals("value 1_1_1", cell1_1_1.getStringCellValue()); | |||
// Verify sheet 2 | |||
XSSFSheet sheet2 = xssfWb3.getSheetAt(1); | |||
assertEquals("S2", sheet2.getSheetName()); | |||
assertEquals(2, sheet2.getPhysicalNumberOfRows()); | |||
Row row2_1 = sheet2.getRow(1); | |||
assertNotNull(row2_1); | |||
Cell cell2_1_1 = row2_1.getCell(1); | |||
assertNotNull(cell2_1_1); | |||
assertEquals("value 2_1_1", cell2_1_1.getStringCellValue()); | |||
XSSFRow row2_2 = sheet2.getRow(2); | |||
assertNotNull(row2_2); | |||
XSSFCell cell2_2_1 = row2_2.getCell(1); | |||
assertNotNull(cell2_2_1); | |||
assertEquals("value 2_2_1", cell2_2_1.getStringCellValue()); | |||
// Verify sheet 3 | |||
XSSFSheet sheet3 = xssfWb3.getSheetAt(2); | |||
assertEquals("S3", sheet3.getSheetName()); | |||
assertEquals(1, sheet3.getPhysicalNumberOfRows()); | |||
XSSFRow row3_1 = sheet3.getRow(1); | |||
assertNotNull(row3_1); | |||
XSSFCell cell3_1_1 = row3_1.getCell(1); | |||
assertNotNull(cell3_1_1); | |||
assertEquals("value 3_1_1", cell3_1_1.getStringCellValue()); | |||
xssfWb2.close(); | |||
xssfWb3.close(); | |||
wb1.close(); | |||
} | |||
@Test | |||
public void sheetdataWriter() throws IOException { | |||
EmittingSXSSFWorkbook wb = new EmittingSXSSFWorkbook(); | |||
SXSSFSheet sh = wb.createSheet(); | |||
assertSame(sh.getClass(), EmittingSXSSFSheet.class); | |||
SheetDataWriter wr = sh.getSheetDataWriter(); | |||
assertNull(wr); | |||
wb.close(); | |||
} | |||
@Test | |||
public void gzipSheetdataWriter() throws IOException { | |||
EmittingSXSSFWorkbook wb = new EmittingSXSSFWorkbook(); | |||
wb.setCompressTempFiles(true); | |||
final int rowNum = 1000; | |||
final int sheetNum = 5; | |||
populateData(wb, 1000, 5); | |||
XSSFWorkbook xwb = SXSSFITestDataProvider.instance.writeOutAndReadBack(wb); | |||
for (int i = 0; i < sheetNum; i++) { | |||
Sheet sh = xwb.getSheetAt(i); | |||
assertEquals("sheet" + i, sh.getSheetName()); | |||
for (int j = 0; j < rowNum; j++) { | |||
Row row = sh.getRow(j); | |||
assertNotNull("row[" + j + "]", row); | |||
Cell cell1 = row.getCell(0); | |||
assertEquals(new CellReference(cell1).formatAsString(), cell1.getStringCellValue()); | |||
Cell cell2 = row.getCell(1); | |||
assertEquals(i, (int) cell2.getNumericCellValue()); | |||
Cell cell3 = row.getCell(2); | |||
assertEquals(j, (int) cell3.getNumericCellValue()); | |||
} | |||
} | |||
assertTrue(wb.dispose()); | |||
xwb.close(); | |||
wb.close(); | |||
} | |||
private static void assertWorkbookDispose(EmittingSXSSFWorkbook wb) { | |||
populateData(wb, 1000, 5); | |||
for (Sheet sheet : wb) { | |||
EmittingSXSSFSheet sxSheet = (EmittingSXSSFSheet) sheet; | |||
assertNull(sxSheet.getSheetDataWriter()); | |||
} | |||
assertTrue(wb.dispose()); | |||
for (Sheet sheet : wb) { | |||
EmittingSXSSFSheet sxSheet = (EmittingSXSSFSheet) sheet; | |||
assertNull(sxSheet.getSheetDataWriter()); | |||
} | |||
} | |||
private static void populateData(EmittingSXSSFWorkbook wb, final int rowNum, final int sheetNum) { | |||
for (int i = 0; i < sheetNum; i++) { | |||
EmittingSXSSFSheet sheet = wb.createSheet("sheet" + i); | |||
int index = i; | |||
sheet.setRowGenerator((sh) -> { | |||
for (int j = 0; j < rowNum; j++) { | |||
Row row = sh.createRow(j); | |||
Cell cell1 = row.createCell(0); | |||
cell1.setCellValue(new CellReference(cell1).formatAsString()); | |||
Cell cell2 = row.createCell(1); | |||
cell2.setCellValue(index); | |||
Cell cell3 = row.createCell(2); | |||
cell3.setCellValue(j); | |||
} | |||
}); | |||
} | |||
} | |||
@Test | |||
public void workbookDispose() throws IOException { | |||
EmittingSXSSFWorkbook wb1 = new EmittingSXSSFWorkbook(); | |||
// the underlying writer is SheetDataWriter | |||
assertWorkbookDispose(wb1); | |||
wb1.close(); | |||
EmittingSXSSFWorkbook wb2 = new EmittingSXSSFWorkbook(); | |||
wb2.setCompressTempFiles(true); | |||
// the underlying writer is GZIPSheetDataWriter | |||
assertWorkbookDispose(wb2); | |||
wb2.close(); | |||
} | |||
@Ignore("currently writing the same sheet multiple times is not supported...") | |||
@Test | |||
public void bug53515() throws Exception { | |||
Workbook wb1 = new SXSSFWorkbook(10); | |||
populateWorkbook(wb1); | |||
saveTwice(wb1); | |||
Workbook wb2 = new XSSFWorkbook(); | |||
populateWorkbook(wb2); | |||
saveTwice(wb2); | |||
wb2.close(); | |||
wb1.close(); | |||
} | |||
@Ignore("Crashes the JVM because of documented JVM behavior with concurrent writing/reading of zip-files, " | |||
+ "see http://www.oracle.com/technetwork/java/javase/documentation/overview-156328.html") | |||
@Test | |||
public void bug53515a() throws Exception { | |||
File out = new File("Test.xlsx"); | |||
assertTrue(!out.exists() || out.delete()); | |||
for (int i = 0; i < 2; i++) { | |||
final SXSSFWorkbook wb; | |||
if (out.exists()) { | |||
wb = new SXSSFWorkbook((XSSFWorkbook) WorkbookFactory.create(out)); | |||
} else { | |||
wb = new SXSSFWorkbook(10); | |||
} | |||
try { | |||
FileOutputStream outSteam = new FileOutputStream(out); | |||
if (i == 0) { | |||
populateWorkbook(wb); | |||
} else { | |||
System.gc(); | |||
System.gc(); | |||
System.gc(); | |||
} | |||
wb.write(outSteam); | |||
// assertTrue(wb.dispose()); | |||
outSteam.close(); | |||
} finally { | |||
assertTrue(wb.dispose()); | |||
} | |||
wb.close(); | |||
} | |||
assertTrue(out.exists()); | |||
assertTrue(out.delete()); | |||
} | |||
private static void populateWorkbook(Workbook wb) { | |||
Sheet sh = wb.createSheet(); | |||
for (int rownum = 0; rownum < 100; rownum++) { | |||
Row row = sh.createRow(rownum); | |||
for (int cellnum = 0; cellnum < 10; cellnum++) { | |||
Cell cell = row.createCell(cellnum); | |||
String address = new CellReference(cell).formatAsString(); | |||
cell.setCellValue(address); | |||
} | |||
} | |||
} | |||
private static void saveTwice(Workbook wb) throws Exception { | |||
for (int i = 0; i < 2; i++) { | |||
try { | |||
NullOutputStream out = new NullOutputStream(); | |||
wb.write(out); | |||
out.close(); | |||
} catch (Exception e) { | |||
throw new Exception("ERROR: failed on " + (i + 1) + "th time calling " + wb.getClass().getName() | |||
+ ".write() with exception " + e.getMessage(), e); | |||
} | |||
} | |||
} | |||
@Test | |||
public void closeDoesNotModifyWorkbook() throws IOException { | |||
final String filename = "SampleSS.xlsx"; | |||
final File file = POIDataSamples.getSpreadSheetInstance().getFile(filename); | |||
// Some tests commented out because close() modifies the file | |||
// See bug 58779 | |||
// String | |||
// wb = new SXSSFWorkbook(new XSSFWorkbook(file.getPath())); | |||
// assertCloseDoesNotModifyFile(filename, wb); | |||
// File | |||
// wb = new SXSSFWorkbook(new XSSFWorkbook(file)); | |||
// assertCloseDoesNotModifyFile(filename, wb); | |||
// InputStream | |||
try (FileInputStream fis = new FileInputStream(file); | |||
XSSFWorkbook xwb = new XSSFWorkbook(fis); | |||
SXSSFWorkbook wb = new SXSSFWorkbook(xwb)) { | |||
assertCloseDoesNotModifyFile(filename, wb); | |||
} | |||
// OPCPackage | |||
// wb = new SXSSFWorkbook(new XSSFWorkbook(OPCPackage.open(file))); | |||
// assertCloseDoesNotModifyFile(filename, wb); | |||
} | |||
/** | |||
* Bug #59743 | |||
* | |||
* this is only triggered on other files apart of sheet[1,2,...].xml as those are either copied uncompressed or with | |||
* the use of GZIPInputStream so we use shared strings | |||
*/ | |||
@Test | |||
public void testZipBombNotTriggeredOnUselessContent() throws IOException { | |||
SXSSFWorkbook swb = new SXSSFWorkbook(null, 1, true, true); | |||
SXSSFSheet s = swb.createSheet(); | |||
char[] useless = new char[32767]; | |||
Arrays.fill(useless, ' '); | |||
for (int row = 0; row < 1; row++) { | |||
Row r = s.createRow(row); | |||
for (int col = 0; col < 10; col++) { | |||
char[] prefix = Integer.toHexString(row * 1000 + col).toCharArray(); | |||
Arrays.fill(useless, 0, 10, ' '); | |||
System.arraycopy(prefix, 0, useless, 0, prefix.length); | |||
String ul = new String(useless); | |||
r.createCell(col, CellType.STRING).setCellValue(ul); | |||
} | |||
} | |||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||
swb.write(bos); | |||
swb.dispose(); | |||
swb.close(); | |||
} | |||
/** | |||
* To avoid accident changes to the template, you should be able to create a SXSSFWorkbook from a read-only XSSF | |||
* one, then change + save that (only). See bug #60010 TODO Fix this to work! | |||
*/ | |||
@Test | |||
@Ignore | |||
public void createFromReadOnlyWorkbook() throws Exception { | |||
String sheetName = "Test SXSSF"; | |||
File input = XSSFTestDataSamples.getSampleFile("sample.xlsx"); | |||
try (OPCPackage pkg = OPCPackage.open(input, PackageAccess.READ)) { | |||
ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |||
try (XSSFWorkbook xssf = new XSSFWorkbook(pkg)) { | |||
try (SXSSFWorkbook wb = new SXSSFWorkbook(xssf, 2)) { | |||
Sheet s = wb.createSheet(sheetName); | |||
for (int i = 0; i < 10; i++) { | |||
Row r = s.createRow(i); | |||
r.createCell(0).setCellValue(true); | |||
r.createCell(1).setCellValue(2.4); | |||
r.createCell(2).setCellValue("Test Row " + i); | |||
} | |||
assertEquals(10, s.getLastRowNum()); | |||
wb.write(bos); | |||
wb.dispose(); | |||
} | |||
} | |||
try (XSSFWorkbook xssf = new XSSFWorkbook(new ByteArrayInputStream(bos.toByteArray()))) { | |||
Sheet s = xssf.getSheet(sheetName); | |||
assertEquals(10, s.getLastRowNum()); | |||
assertTrue(s.getRow(0).getCell(0).getBooleanCellValue()); | |||
assertEquals("Test Row 9", s.getRow(9).getCell(2).getStringCellValue()); | |||
} | |||
} | |||
} | |||
@Test | |||
public void test56557() throws IOException { | |||
Workbook wb = XSSFTestDataSamples.openSampleWorkbook("56557.xlsx"); | |||
// Using streaming XSSFWorkbook makes the output file invalid | |||
wb = new SXSSFWorkbook(((XSSFWorkbook) wb)); | |||
// Should not throw POIXMLException: java.io.IOException: Unable to parse xml bean when reading back | |||
Workbook wbBack = XSSFTestDataSamples.writeOutAndReadBack(wb); | |||
assertNotNull(wbBack); | |||
wbBack.close(); | |||
wb.close(); | |||
} | |||
} |