mirror of https://github.com/apache/poi.git
[github-184] New EmittingSXSSFWorkbook. Thanks to mobreza. This closes #184
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1879302 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
09d81ea7da
commit
f06c45421b
|
@ -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,12 +106,14 @@ public final class SXSSFFormulaEvaluator extends BaseXSSFFormulaEvaluator {
|
||||||
// Process the sheets as best we can
|
// Process the sheets as best we can
|
||||||
for (Sheet sheet : wb) {
|
for (Sheet sheet : wb) {
|
||||||
|
|
||||||
|
if (sheet instanceof SXSSFSheet) {
|
||||||
// Check if any rows have already been flushed out
|
// Check if any rows have already been flushed out
|
||||||
int lastFlushedRowNum = ((SXSSFSheet) sheet).getLastFlushedRowNum();
|
int lastFlushedRowNum = ((SXSSFSheet) sheet).getLastFlushedRowNum();
|
||||||
if (lastFlushedRowNum > -1) {
|
if (lastFlushedRowNum > -1) {
|
||||||
if (! skipOutOfWindow) throw new RowFlushedException(0);
|
if (! skipOutOfWindow) throw new RowFlushedException(0);
|
||||||
logger.log(POILogger.INFO, "Rows up to " + lastFlushedRowNum + " have already been flushed, skipping");
|
logger.log(POILogger.INFO, "Rows up to " + lastFlushedRowNum + " have already been flushed, skipping");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Evaluate what we have
|
// Evaluate what we have
|
||||||
for (Row r : sheet) {
|
for (Row r : sheet) {
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.poi.openxml4j.opc.PackagePart;
|
||||||
import org.apache.poi.ss.usermodel.Picture;
|
import org.apache.poi.ss.usermodel.Picture;
|
||||||
import org.apache.poi.ss.usermodel.Row;
|
import org.apache.poi.ss.usermodel.Row;
|
||||||
import org.apache.poi.ss.usermodel.Shape;
|
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.usermodel.Workbook;
|
||||||
import org.apache.poi.ss.util.ImageUtils;
|
import org.apache.poi.ss.util.ImageUtils;
|
||||||
import org.apache.poi.util.Internal;
|
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,
|
// 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)
|
// not the XSSF sheet (which never contais rows when using SXSSF)
|
||||||
XSSFSheet xssfSheet = getSheet();
|
XSSFSheet xssfSheet = getSheet();
|
||||||
SXSSFSheet sheet = _wb.getSXSSFSheet(xssfSheet);
|
SXSSFSheet sxSheet = _wb.getSXSSFSheet(xssfSheet);
|
||||||
|
Sheet sheet = sxSheet == null ? xssfSheet : sxSheet;
|
||||||
Row row = sheet.getRow(rowIndex);
|
Row row = sheet.getRow(rowIndex);
|
||||||
float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
float height = row != null ? row.getHeightInPoints() : sheet.getDefaultRowHeightInPoints();
|
||||||
return height * Units.PIXEL_DPI / Units.POINT_DPI;
|
return height * Units.PIXEL_DPI / Units.POINT_DPI;
|
||||||
|
|
|
@ -65,15 +65,22 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorksheet;
|
||||||
public class SXSSFSheet implements Sheet
|
public class SXSSFSheet implements Sheet
|
||||||
{
|
{
|
||||||
/*package*/ final XSSFSheet _sh;
|
/*package*/ final XSSFSheet _sh;
|
||||||
private final SXSSFWorkbook _workbook;
|
protected final SXSSFWorkbook _workbook;
|
||||||
private final TreeMap<Integer,SXSSFRow> _rows = new TreeMap<>();
|
private final TreeMap<Integer,SXSSFRow> _rows = new TreeMap<>();
|
||||||
private final SheetDataWriter _writer;
|
protected SheetDataWriter _writer;
|
||||||
private int _randomAccessWindowSize = SXSSFWorkbook.DEFAULT_WINDOW_SIZE;
|
private int _randomAccessWindowSize = SXSSFWorkbook.DEFAULT_WINDOW_SIZE;
|
||||||
private final AutoSizeColumnTracker _autoSizeColumnTracker;
|
protected final AutoSizeColumnTracker _autoSizeColumnTracker;
|
||||||
private int outlineLevelRow;
|
private int outlineLevelRow;
|
||||||
private int lastFlushedRowNumber = -1;
|
private int lastFlushedRowNumber = -1;
|
||||||
private boolean allFlushed;
|
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 {
|
public SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException {
|
||||||
_workbook = workbook;
|
_workbook = workbook;
|
||||||
_sh = xSheet;
|
_sh = xSheet;
|
||||||
|
@ -1904,7 +1911,7 @@ public class SXSSFSheet implements Sheet
|
||||||
if (!allFlushed) {
|
if (!allFlushed) {
|
||||||
flushRows();
|
flushRows();
|
||||||
}
|
}
|
||||||
return _writer.dispose();
|
return _writer == null || _writer.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -96,13 +96,17 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
public static final int DEFAULT_WINDOW_SIZE = 100;
|
public static final int DEFAULT_WINDOW_SIZE = 100;
|
||||||
private static final POILogger logger = POILogFactory.getLogger(SXSSFWorkbook.class);
|
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<SXSSFSheet,XSSFSheet> _sxFromXHash = new HashMap<>();
|
||||||
private final Map<XSSFSheet,SXSSFSheet> _xFromSxHash = new HashMap<>();
|
private final Map<XSSFSheet,SXSSFSheet> _xFromSxHash = new HashMap<>();
|
||||||
|
|
||||||
private int _randomAccessWindowSize = DEFAULT_WINDOW_SIZE;
|
private int _randomAccessWindowSize = DEFAULT_WINDOW_SIZE;
|
||||||
|
|
||||||
|
protected static interface ISheetInjector {
|
||||||
|
void writeSheetData(OutputStream out) throws IOException;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* whether temp files should be compressed.
|
* whether temp files should be compressed.
|
||||||
*/
|
*/
|
||||||
|
@ -111,12 +115,12 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
/**
|
/**
|
||||||
* shared string table - a cache of strings in this 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
|
* 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
|
* Construct a new workbook with default row window size
|
||||||
|
@ -285,7 +289,7 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
return _randomAccessWindowSize;
|
return _randomAccessWindowSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setRandomAccessWindowSize(int rowAccessWindowSize) {
|
protected void setRandomAccessWindowSize(int rowAccessWindowSize) {
|
||||||
if(rowAccessWindowSize == 0 || rowAccessWindowSize < -1) {
|
if(rowAccessWindowSize == 0 || rowAccessWindowSize < -1) {
|
||||||
throw new IllegalArgumentException("rowAccessWindowSize must be greater than 0 or -1");
|
throw new IllegalArgumentException("rowAccessWindowSize must be greater than 0 or -1");
|
||||||
}
|
}
|
||||||
|
@ -377,7 +381,7 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
_xFromSxHash.remove(xSheet);
|
_xFromSxHash.remove(xSheet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private XSSFSheet getSheetFromZipEntryName(String sheetRef)
|
protected XSSFSheet getSheetFromZipEntryName(String sheetRef)
|
||||||
{
|
{
|
||||||
for(XSSFSheet sheet : _sxFromXHash.values())
|
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
|
// See bug 56557, we should not inject data into the special ChartSheets
|
||||||
if (xSheet != null && !(xSheet instanceof XSSFChartSheet)) {
|
if (xSheet != null && !(xSheet instanceof XSSFChartSheet)) {
|
||||||
SXSSFSheet sxSheet = getSXSSFSheet(xSheet);
|
SXSSFSheet sxSheet = getSXSSFSheet(xSheet);
|
||||||
try (InputStream xis = sxSheet.getWorksheetXMLInputStream()) {
|
copyStreamAndInjectWorksheet(is, zos, createSheetInjector(sxSheet));
|
||||||
copyStreamAndInjectWorksheet(is, zos, xis);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
IOUtils.copy(is, zos);
|
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);
|
InputStreamReader inReader = new InputStreamReader(in, StandardCharsets.UTF_8);
|
||||||
OutputStreamWriter outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
OutputStreamWriter outWriter = new OutputStreamWriter(out, StandardCharsets.UTF_8);
|
||||||
boolean needsStartTag = true;
|
boolean needsStartTag = true;
|
||||||
|
@ -526,8 +538,7 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
outWriter.write("<sheetData>\n");
|
outWriter.write("<sheetData>\n");
|
||||||
outWriter.flush();
|
outWriter.flush();
|
||||||
}
|
}
|
||||||
//Copy the worksheet data to "out".
|
sheetInjector.writeSheetData(out);
|
||||||
IOUtils.copy(worksheetData,out);
|
|
||||||
outWriter.write("</sheetData>");
|
outWriter.write("</sheetData>");
|
||||||
outWriter.flush();
|
outWriter.flush();
|
||||||
//Copy the rest of "in" to "out".
|
//Copy the rest of "in" to "out".
|
||||||
|
@ -918,7 +929,8 @@ public class SXSSFWorkbook implements Workbook {
|
||||||
for (SXSSFSheet sheet : _xFromSxHash.values())
|
for (SXSSFSheet sheet : _xFromSxHash.values())
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
sheet.getSheetDataWriter().close();
|
SheetDataWriter _writer = sheet.getSheetDataWriter();
|
||||||
|
if (_writer != null) _writer.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.log(POILogger.WARN,
|
logger.log(POILogger.WARN,
|
||||||
"An exception occurred while closing sheet data writer for sheet "
|
"An exception occurred while closing sheet data writer for sheet "
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class SheetDataWriter implements Closeable {
|
||||||
private static final POILogger logger = POILogFactory.getLogger(SheetDataWriter.class);
|
private static final POILogger logger = POILogFactory.getLogger(SheetDataWriter.class);
|
||||||
|
|
||||||
private final File _fd;
|
private final File _fd;
|
||||||
private final Writer _out;
|
protected final Writer _out;
|
||||||
private int _rownum;
|
private int _rownum;
|
||||||
private int _numberOfFlushedRows;
|
private int _numberOfFlushedRows;
|
||||||
private int _lowestIndexOfFlushedRows; // meaningful only of _numberOfFlushedRows>0
|
private int _lowestIndexOfFlushedRows; // meaningful only of _numberOfFlushedRows>0
|
||||||
|
@ -73,6 +73,11 @@ public class SheetDataWriter implements Closeable {
|
||||||
_out = createWriter(_fd);
|
_out = createWriter(_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public SheetDataWriter(Writer writer) throws IOException {
|
||||||
|
_fd = null;
|
||||||
|
_out = writer;
|
||||||
|
}
|
||||||
|
|
||||||
public SheetDataWriter(SharedStringsTable sharedStringsTable) throws IOException {
|
public SheetDataWriter(SharedStringsTable sharedStringsTable) throws IOException {
|
||||||
this();
|
this();
|
||||||
this._sharedStringSource = sharedStringsTable;
|
this._sharedStringSource = sharedStringsTable;
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue