123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353 |
- /* ====================================================================
- 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.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.io.OutputStreamWriter;
- import java.nio.charset.StandardCharsets;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.NoSuchElementException;
-
- import org.apache.commons.compress.archivers.ArchiveOutputStream;
- import org.apache.commons.compress.archivers.zip.Zip64Mode;
- import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
- import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
- import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
- import org.apache.commons.io.output.UnsynchronizedByteArrayOutputStream;
- import org.apache.logging.log4j.LogManager;
- import org.apache.logging.log4j.Logger;
- import org.apache.poi.openxml4j.opc.OPCPackage;
- import org.apache.poi.openxml4j.util.ZipArchiveThresholdInputStream;
- import org.apache.poi.openxml4j.util.ZipEntrySource;
- import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
- import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
- import org.apache.poi.openxml4j.util.ZipSecureFile;
- import org.apache.poi.ss.SpreadsheetVersion;
- import org.apache.poi.ss.formula.EvaluationWorkbook;
- import org.apache.poi.ss.formula.udf.UDFFinder;
- import org.apache.poi.ss.usermodel.CellStyle;
- import org.apache.poi.ss.usermodel.CreationHelper;
- import org.apache.poi.ss.usermodel.DataFormat;
- import org.apache.poi.ss.usermodel.Font;
- import org.apache.poi.ss.usermodel.Name;
- import org.apache.poi.ss.usermodel.PictureData;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.SheetVisibility;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.util.Beta;
- import org.apache.poi.util.IOUtils;
- import org.apache.poi.util.Internal;
- import org.apache.poi.util.NotImplemented;
- import org.apache.poi.util.Removal;
- import org.apache.poi.util.TempFile;
- import org.apache.poi.xssf.model.SharedStringsTable;
- import org.apache.poi.xssf.usermodel.XSSFChartSheet;
- import org.apache.poi.xssf.usermodel.XSSFSheet;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- /**
- * Streaming version of XSSFWorkbook implementing the "BigGridDemo" strategy.
- *
- * This allows to write very large files without running out of memory as only
- * a configurable portion of the rows are kept in memory at any one time.
- *
- * You can provide a template workbook which is used as basis for the written
- * data.
- *
- * See https://poi.apache.org/spreadsheet/how-to.html#sxssf for details.
- *
- * Please note that there are still things that still may consume a large
- * amount of memory based on which features you are using, e.g. merged regions,
- * comments, ... are still only stored in memory and thus may require a lot of
- * memory if used extensively.
- *
- * SXSSFWorkbook defaults to using inline strings instead of a shared strings
- * table. This is very efficient, since no document content needs to be kept in
- * memory, but is also known to produce documents that are incompatible with
- * some clients. With shared strings enabled all unique strings in the document
- * has to be kept in memory. Depending on your document content this could use
- * a lot more resources than with shared strings disabled.
- *
- * Carefully review your memory budget and compatibility needs before deciding
- * whether to enable shared strings or not.
- */
- public class SXSSFWorkbook implements Workbook {
- /**
- * Specifies how many rows can be accessed at most via {@link SXSSFSheet#getRow}.
- * When a new node is created via {@link SXSSFSheet#createRow} and the total number
- * of unflushed records would exceed the specified value, then the
- * row with the lowest index value is flushed and cannot be accessed
- * via {@link SXSSFSheet#getRow} anymore.
- */
- public static final int DEFAULT_WINDOW_SIZE = 100;
- private static final Logger LOG = LogManager.getLogger(SXSSFWorkbook.class);
-
- 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 interface ISheetInjector {
- void writeSheetData(OutputStream out) throws IOException;
- }
-
- /**
- * whether temp files should be compressed.
- */
- private boolean _compressTmpFiles;
-
- /**
- * shared string table - a cache of strings in this workbook
- */
- protected final SharedStringsTable _sharedStringSource;
-
- /**
- * controls whether Zip64 mode is used - Always became the default in POI 5.0.0
- */
- protected Zip64Mode zip64Mode = Zip64Mode.Always;
-
- /**
- * Construct a new workbook with default row window size
- */
- public SXSSFWorkbook(){
- this(null /*workbook*/);
- }
-
- /**
- * <p>Construct a workbook from a template.</p>
- *
- * There are three use-cases to use SXSSFWorkbook(XSSFWorkbook) :
- * <ol>
- * <li>
- * Append new sheets to existing workbooks. You can open existing
- * workbook from a file or create on the fly with XSSF.
- * </li>
- * <li>
- * Append rows to existing sheets. The row number MUST be greater
- * than {@code max(rownum)} in the template sheet.
- * </li>
- * <li>
- * Use existing workbook as a template and re-use global objects such
- * as cell styles, formats, images, etc.
- * </li>
- * </ol>
- * All three use cases can work in a combination.
- *
- * What is not supported:
- * <ul>
- * <li>
- * Access initial cells and rows in the template. After constructing
- * all internal windows are empty and {@link SXSSFSheet#getRow} and
- * {@link SXSSFRow#getCell} return <code>null</code>.
- * </li>
- * <li>
- * Override existing cells and rows. The API silently allows that but
- * the output file is invalid and Excel cannot read it.
- * </li>
- * </ul>
- *
- * @param workbook the template workbook
- */
- public SXSSFWorkbook(XSSFWorkbook workbook){
- this(workbook, DEFAULT_WINDOW_SIZE);
- }
-
-
- /**
- * Constructs an workbook from an existing workbook.
- * <p>
- * When a new node is created via {@link SXSSFSheet#createRow} and the total number
- * of unflushed records would exceed the specified value, then the
- * row with the lowest index value is flushed and cannot be accessed
- * via {@link SXSSFSheet#getRow} anymore.
- * </p>
- * <p>
- * A value of <code>-1</code> indicates unlimited access. In this case all
- * records that have not been flushed by a call to <code>flush()</code> are available
- * for random access.
- * </p>
- * <p>
- * A value of <code>0</code> is not allowed because it would flush any newly created row
- * without having a chance to specify any cells.
- * </p>
- *
- * @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);
- }
-
- /**
- * Constructs an workbook from an existing workbook.
- * <p>
- * When a new node is created via {@link SXSSFSheet#createRow} and the total number
- * of unflushed records would exceed the specified value, then the
- * row with the lowest index value is flushed and cannot be accessed
- * via {@link SXSSFSheet#getRow} anymore.
- * </p>
- * <p>
- * A value of <code>-1</code> indicates unlimited access. In this case all
- * records that have not been flushed by a call to <code>flush()</code> are available
- * for random access.
- * </p>
- * <p>
- * A value of <code>0</code> is not allowed because it would flush any newly created row
- * without having a chance to specify any cells.
- * </p>
- *
- * @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);
- }
-
- /**
- * Constructs an workbook from an existing workbook.
- * <p>
- * When a new node is created via {@link SXSSFSheet#createRow} and the total number
- * of unflushed records would exceed the specified value, then the
- * row with the lowest index value is flushed and cannot be accessed
- * via {@link SXSSFSheet#getRow} anymore.
- * </p>
- * <p>
- * A value of <code>-1</code> indicates unlimited access. In this case all
- * records that have not been flushed by a call to <code>flush()</code> are available
- * for random access.
- * </p>
- * <p>
- * A value of <code>0</code> is not allowed because it would flush any newly created row
- * without having a chance to specify any cells.
- * </p>
- *
- * @param workbook the template 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
- * @param useSharedStringsTable whether to use a shared strings table
- */
- public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable) {
- setRandomAccessWindowSize(rowAccessWindowSize);
- setCompressTempFiles(compressTmpFiles);
- if (workbook == null) {
- _wb = new XSSFWorkbook();
- _sharedStringSource = useSharedStringsTable ? _wb.getSharedStringSource() : null;
- } else {
- _wb=workbook;
- _sharedStringSource = useSharedStringsTable ? _wb.getSharedStringSource() : null;
- for ( Sheet sheet : _wb ) {
- createAndRegisterSXSSFSheet( (XSSFSheet)sheet );
- }
- }
- }
-
- /**
- * Construct an empty workbook and specify the window for row access.
- * <p>
- * When a new node is created via {@link SXSSFSheet#createRow} and the total number
- * of unflushed records would exceed the specified value, then the
- * row with the lowest index value is flushed and cannot be accessed
- * via {@link SXSSFSheet#getRow} anymore.
- * </p>
- * <p>
- * A value of <code>-1</code> indicates unlimited access. In this case all
- * records that have not been flushed by a call to <code>flush()</code> are available
- * for random access.
- * </p>
- * <p>
- * A value of <code>0</code> is not allowed because it would flush any newly created row
- * without having a chance to specify any cells.
- * </p>
- *
- * @param rowAccessWindowSize the number of rows that are kept in memory until flushed out, see above.
- */
- public SXSSFWorkbook(int rowAccessWindowSize){
- this(null /*workbook*/, rowAccessWindowSize);
- }
-
- /**
- * See the constructors for a more detailed description of the sliding window of rows.
- *
- * @return The number of rows that are kept in memory at once before flushing them out.
- */
- public int getRandomAccessWindowSize() {
- return _randomAccessWindowSize;
- }
-
- protected void setRandomAccessWindowSize(int rowAccessWindowSize) {
- if(rowAccessWindowSize == 0 || rowAccessWindowSize < -1) {
- throw new IllegalArgumentException("rowAccessWindowSize must be greater than 0 or -1");
- }
- _randomAccessWindowSize = rowAccessWindowSize;
- }
-
- /**
- * @param zip64Mode {@link Zip64Mode}
- *
- * @since 4.1.0
- */
- @Beta
- public void setZip64Mode(Zip64Mode zip64Mode) {
- this.zip64Mode = zip64Mode;
- }
-
- /**
- * Get whether temp files should be compressed.
- *
- * @return whether to compress temp files
- */
- public boolean isCompressTempFiles() {
- return _compressTmpFiles;
- }
-
- /**
- * Set whether temp files should be compressed.
- * <p>
- * SXSSF writes sheet data in temporary files (a temp file per-sheet)
- * and the size of these temp files can grow to to a very large size,
- * e.g. for a 20 MB csv data the size of the temp xml file become few GB large.
- * If the "compress" flag is set to <code>true</code> then the temporary XML is gzipped.
- * </p>
- * <p>
- * Please note the the "compress" option may cause performance penalty.
- * </p>
- * <p>
- * Setting this option only affects compression for subsequent <code>createSheet()</code>
- * calls.
- * </p>
- * @param compress whether to compress temp files
- */
- public void setCompressTempFiles(boolean compress) {
- _compressTmpFiles = compress;
- }
-
- @Internal
- protected SharedStringsTable getSharedStringSource() {
- return _sharedStringSource;
- }
-
- protected SheetDataWriter createSheetDataWriter() throws IOException {
- if(_compressTmpFiles) {
- return new GZIPSheetDataWriter(_sharedStringSource);
- }
-
- return new SheetDataWriter(_sharedStringSource);
- }
-
- XSSFSheet getXSSFSheet(SXSSFSheet sheet)
- {
- return _sxFromXHash.get(sheet);
- }
-
- SXSSFSheet getSXSSFSheet(XSSFSheet sheet)
- {
- return _xFromSxHash.get(sheet);
- }
-
- void registerSheetMapping(SXSSFSheet sxSheet,XSSFSheet xSheet)
- {
- _sxFromXHash.put(sxSheet,xSheet);
- _xFromSxHash.put(xSheet,sxSheet);
- }
-
- void deregisterSheetMapping(XSSFSheet xSheet)
- {
- SXSSFSheet sxSheet = getSXSSFSheet(xSheet);
- if (sxSheet != null) {
- // ensure that the writer is closed in all cases to not have lingering writers
- IOUtils.closeQuietly(sxSheet.getSheetDataWriter());
- _sxFromXHash.remove(sxSheet);
- _xFromSxHash.remove(xSheet);
- }
- }
-
- protected XSSFSheet getSheetFromZipEntryName(String sheetRef)
- {
- for(XSSFSheet sheet : _sxFromXHash.values())
- {
- if(sheetRef.equals(sheet.getPackagePart().getPartName().getName().substring(1))) {
- return sheet;
- }
- }
- return null;
- }
-
- protected void injectData(ZipEntrySource zipEntrySource, OutputStream out) throws IOException {
- ArchiveOutputStream zos = createArchiveOutputStream(out);
- try {
- Enumeration<? extends ZipArchiveEntry> en = zipEntrySource.getEntries();
- while (en.hasMoreElements()) {
- ZipArchiveEntry ze = en.nextElement();
- ZipArchiveEntry zeOut = new ZipArchiveEntry(ze.getName());
- if (ze.getSize() >= 0) zeOut.setSize(ze.getSize());
- if (ze.getTime() >= 0) zeOut.setTime(ze.getTime());
- zos.putArchiveEntry(zeOut);
- try (final InputStream is = zipEntrySource.getInputStream(ze)) {
- if (is instanceof ZipArchiveThresholdInputStream) {
- // #59743 - disable Threshold handling for SXSSF copy
- // as users tend to put too much repetitive data in when using SXSSF :)
- ((ZipArchiveThresholdInputStream)is).setGuardState(false);
- }
- XSSFSheet xSheet = getSheetFromZipEntryName(ze.getName());
- // See bug 56557, we should not inject data into the special ChartSheets
- if (xSheet != null && !(xSheet instanceof XSSFChartSheet)) {
- SXSSFSheet sxSheet = getSXSSFSheet(xSheet);
- copyStreamAndInjectWorksheet(is, zos, createSheetInjector(sxSheet));
- } else {
- IOUtils.copy(is, zos);
- }
- } finally {
- zos.closeArchiveEntry();
- }
- }
- } finally {
- zos.finish();
- zipEntrySource.close();
- }
- }
-
- protected ZipArchiveOutputStream createArchiveOutputStream(OutputStream out) {
- if (Zip64Mode.Always.equals(zip64Mode)) {
- return new OpcZipArchiveOutputStream(out);
- } else {
- ZipArchiveOutputStream zos = new ZipArchiveOutputStream(out);
- zos.setUseZip64(zip64Mode);
- return zos;
- }
- }
-
- 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;
- int c;
- int pos=0;
- String s="<sheetData";
- int n=s.length();
- //Copy from "in" to "out" up to the string "<sheetData/>" or "</sheetData>" (excluding).
- while(((c=inReader.read())!=-1))
- {
- if(c==s.charAt(pos))
- {
- 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;
- }
- }
- }
- else
- {
- if(pos>0) {
- outWriter.write(s,0,pos);
- }
- if(c==s.charAt(0))
- {
- pos=1;
- }
- else
- {
- outWriter.write(c);
- pos=0;
- }
- }
- }
- outWriter.flush();
- if (needsStartTag)
- {
- outWriter.write("<sheetData>\n");
- outWriter.flush();
- }
- sheetInjector.writeSheetData(out);
- outWriter.write("</sheetData>");
- outWriter.flush();
- //Copy the rest of "in" to "out".
- while(((c=inReader.read())!=-1)) {
- outWriter.write(c);
- }
- outWriter.flush();
- }
-
- public XSSFWorkbook getXSSFWorkbook()
- {
- return _wb;
- }
-
- //start of interface implementation
-
- /**
- * Convenience method to get the active sheet. The active sheet is is the sheet
- * which is currently displayed when the workbook is viewed in Excel.
- * 'Selected' sheet(s) is a distinct concept.
- *
- * @return the index of the active sheet (0-based)
- */
- @Override
- public int getActiveSheetIndex()
- {
- return _wb.getActiveSheetIndex();
- }
-
- /**
- * Convenience method to set the active sheet. The active sheet is is the sheet
- * which is currently displayed when the workbook is viewed in Excel.
- * 'Selected' sheet(s) is a distinct concept.
- *
- * @param sheetIndex index of the active sheet (0-based)
- */
- @Override
- public void setActiveSheet(int sheetIndex)
- {
- _wb.setActiveSheet(sheetIndex);
- }
-
- /**
- * Gets the first tab that is displayed in the list of tabs in excel.
- *
- * @return the first tab that to display in the list of tabs (0-based).
- */
- @Override
- public int getFirstVisibleTab()
- {
- return _wb.getFirstVisibleTab();
- }
-
- /**
- * Sets the first tab that is displayed in the list of tabs in excel.
- *
- * @param sheetIndex the first tab that to display in the list of tabs (0-based)
- */
- @Override
- public void setFirstVisibleTab(int sheetIndex)
- {
- _wb.setFirstVisibleTab(sheetIndex);
- }
-
- /**
- * Sets the order of appearance for a given sheet.
- *
- * @param sheetname the name of the sheet to reorder
- * @param pos the position that we want to insert the sheet into (0 based)
- */
- @Override
- public void setSheetOrder(String sheetname, int pos)
- {
- _wb.setSheetOrder(sheetname,pos);
- }
-
- /**
- * Sets the tab whose data is actually seen when the sheet is opened.
- * This may be different from the "selected sheet" since excel seems to
- * allow you to show the data of one sheet when another is seen "selected"
- * in the tabs (at the bottom).
- *
- * @see Sheet#setSelected(boolean)
- * @param index the index of the sheet to select (0 based)
- */
- @Override
- public void setSelectedTab(int index)
- {
- _wb.setSelectedTab(index);
- }
-
- /**
- * Set the sheet name.
- *
- * @param sheet number (0 based)
- * @throws IllegalArgumentException if the name is greater than 31 chars or contains <code>/\?*[]</code>
- */
- @Override
- public void setSheetName(int sheet, String name)
- {
- _wb.setSheetName(sheet,name);
- }
-
- /**
- * Set the sheet name
- *
- * @param sheet sheet number (0 based)
- * @return Sheet name
- */
- @Override
- public String getSheetName(int sheet)
- {
- return _wb.getSheetName(sheet);
- }
-
- /**
- * Returns the index of the sheet by his name
- *
- * @param name the sheet name
- * @return index of the sheet (0 based)
- */
- @Override
- public int getSheetIndex(String name)
- {
- return _wb.getSheetIndex(name);
- }
-
- /**
- * Returns the index of the given sheet
- *
- * @param sheet the sheet to look up
- * @return index of the sheet (0 based)
- */
- @Override
- public int getSheetIndex(Sheet sheet)
- {
- return _wb.getSheetIndex(getXSSFSheet((SXSSFSheet)sheet));
- }
-
- /**
- * Create a Sheet for this Workbook, adds it to the sheets and returns
- * the high level representation. Use this to create new sheets.
- *
- * @return Sheet representing the new sheet.
- */
- @Override
- public SXSSFSheet createSheet()
- {
- return createAndRegisterSXSSFSheet(_wb.createSheet());
- }
-
- SXSSFSheet createAndRegisterSXSSFSheet(XSSFSheet xSheet) {
- final SXSSFSheet sxSheet;
- try {
- sxSheet = new SXSSFSheet(this,xSheet);
- } catch (IOException ioe) {
- throw new RuntimeException(ioe);
- }
- registerSheetMapping(sxSheet,xSheet);
- return sxSheet;
- }
-
- /**
- * Create a Sheet for this Workbook, adds it to the sheets and returns
- * the high level representation. Use this to create new sheets.
- *
- * @param sheetname sheetname to set for the sheet.
- * @return Sheet representing the new sheet.
- * @throws IllegalArgumentException if the name is greater than 31 chars or contains <code>/\?*[]</code>
- */
- @Override
- public SXSSFSheet createSheet(String sheetname)
- {
- return createAndRegisterSXSSFSheet(_wb.createSheet(sheetname));
- }
-
- /**
- * <i>Not implemented for SXSSFWorkbook</i>
- *
- * Create a Sheet from an existing sheet in the Workbook.
- *
- * @return Sheet representing the cloned sheet.
- */
- @Override
- @NotImplemented
- public Sheet cloneSheet(int sheetNum) {
- throw new RuntimeException("Not Implemented");
- }
-
-
- /**
- * Get the number of spreadsheets in the workbook
- *
- * @return the number of sheets
- */
- @Override
- public int getNumberOfSheets()
- {
- return _wb.getNumberOfSheets();
- }
-
- /**
- * 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<>();
- }
-
- protected 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();
- return (T) getSXSSFSheet(xssfSheet);
- }
- /**
- * 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();
- }
-
- /**
- * Get the Sheet object at the given index.
- *
- * @param index of the sheet number (0-based physical and logical)
- * @return Sheet at the provided index
- */
- @Override
- public SXSSFSheet getSheetAt(int index)
- {
- return getSXSSFSheet(_wb.getSheetAt(index));
- }
-
- /**
- * Get sheet with the given name
- *
- * @param name of the sheet
- * @return Sheet with the name provided or <code>null</code> if it does not exist
- */
- @Override
- public SXSSFSheet getSheet(String name)
- {
- return getSXSSFSheet(_wb.getSheet(name));
- }
-
- /**
- * 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);
- deregisterSheetMapping(xSheet);
-
- // Clean up temporary resources
- try {
- sxSheet.dispose();
- } catch (IOException e) {
- LOG.atWarn().withThrowable(e).log("Failed to dispose old sheet");
- }
- }
-
- /**
- * Create a new Font and add it to the workbook's font table
- *
- * @return new font object
- */
- @Override
- public Font createFont()
- {
- return _wb.createFont();
- }
-
- /**
- * Finds a font that matches the one with the supplied attributes
- *
- * @return the font with the matched attributes or <code>null</code>
- */
- @Override
- public Font findFont(boolean bold, short color, short fontHeight, String name, boolean italic, boolean strikeout, short typeOffset, byte underline)
- {
- return _wb.findFont(bold, color, fontHeight, name, italic, strikeout, typeOffset, underline);
- }
-
- @Override
- public int getNumberOfFonts() {
- return _wb.getNumberOfFonts();
- }
-
- @Override
- @Deprecated
- @Removal(version = "6.0.0")
- public int getNumberOfFontsAsInt()
- {
- return getNumberOfFonts();
- }
-
- @Override
- public Font getFontAt(int idx)
- {
- return _wb.getFontAt(idx);
- }
-
- /**
- * Create a new Cell style and add it to the workbook's style table
- *
- * @return the new Cell Style object
- */
- @Override
- public CellStyle createCellStyle()
- {
- return _wb.createCellStyle();
- }
-
- /**
- * Get the number of styles the workbook contains
- *
- * @return count of cell styles
- */
- @Override
- public int getNumCellStyles()
- {
- return _wb.getNumCellStyles();
- }
-
- /**
- * Get the cell style object at the given index
- *
- * @param idx index within the set of styles (0-based)
- * @return CellStyle object at the index
- */
- @Override
- public CellStyle getCellStyleAt(int idx)
- {
- return _wb.getCellStyleAt(idx);
- }
-
- /**
- * Closes the underlying {@link XSSFWorkbook} and {@link OPCPackage}
- * on which this Workbook is based, if any.
- *
- * <p>Once this has been called, no further
- * operations, updates or reads should be performed on the
- * Workbook.
- */
- @Override
- public void close() throws IOException {
- // ensure that any lingering writer is closed
- for (SXSSFSheet sheet : _xFromSxHash.values())
- {
- try {
- SheetDataWriter _writer = sheet.getSheetDataWriter();
- if (_writer != null) _writer.close();
- } catch (IOException e) {
- LOG.atWarn().withThrowable(e).log("An exception occurred while closing sheet data writer for sheet {}.", sheet.getSheetName());
- }
- }
-
-
- // Tell the base workbook to close, does nothing if
- // it's a newly created one
- _wb.close();
- }
-
- /**
- * Write out this workbook to an OutputStream.
- *
- * @param stream - the java OutputStream you wish to write to
- * @throws IOException if anything can't be written.
- */
- @Override
- public void write(OutputStream stream) throws IOException {
- flushSheets();
-
- //Save the template
- File tmplFile = TempFile.createTempFile("poi-sxssf-template", ".xlsx");
- boolean deleted;
- try {
- try (FileOutputStream os = new FileOutputStream(tmplFile)) {
- _wb.write(os);
- }
-
- //Substitute the template entries with the generated sheet data files
- try (ZipSecureFile zf = new ZipSecureFile(tmplFile);
- ZipFileZipEntrySource source = new ZipFileZipEntrySource(zf)) {
- injectData(source, stream);
- }
- } finally {
- deleted = tmplFile.delete();
- }
- if (!deleted) {
- throw new IOException("Could not delete temporary file after processing: " + tmplFile);
- }
- }
-
- /**
- * Write out this workbook to an OutputStream. This (experimental) method avoids the temp file that
- * {@link #write} creates but will use more memory as a result. Other SXSSF code can create temp files,
- * so using this does not guarantee that there will be no temp file usage.
- *
- * @param stream - the java OutputStream you wish to write to
- * @throws IOException if anything can't be written.
- * @since POI 5.1.0 (experimental and still liable to change or be removed)
- */
- @Beta
- public void writeAvoidingTempFiles(OutputStream stream) throws IOException {
- flushSheets();
-
- //Save the template
- try (UnsynchronizedByteArrayOutputStream bos = new UnsynchronizedByteArrayOutputStream()) {
- _wb.write(bos);
-
- //Substitute the template entries with the generated sheet data files
- try (
- InputStream is = bos.toInputStream();
- ZipInputStreamZipEntrySource source = new ZipInputStreamZipEntrySource(
- new ZipArchiveThresholdInputStream(new ZipArchiveInputStream(is)))
- ) {
- injectData(source, stream);
- }
- }
- }
-
- 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.
- * @return true if all temporary files were deleted successfully.
- */
- public boolean dispose()
- {
- boolean success = true;
- for (SXSSFSheet sheet : _sxFromXHash.keySet())
- {
- try {
- success = sheet.dispose() && success;
- } catch (IOException e) {
- LOG.atWarn().withThrowable(e).log("Failed to dispose sheet");
- success = false;
- }
- }
- return success;
- }
-
- /**
- * @return the total number of defined names in this workbook
- */
- @Override
- public int getNumberOfNames()
- {
- return _wb.getNumberOfNames();
- }
-
- /**
- * @param name the name of the defined name
- * @return the defined name with the specified name. <code>null</code> if not found.
- */
- @Override
- public Name getName(String name)
- {
- return _wb.getName(name);
- }
-
- /**
- * Returns all defined names with the given name.
- *
- * @param name the name of the defined name
- * @return a list of the defined names with the specified name. An empty list is returned if none is found.
- */
- @Override
- public List<? extends Name> getNames(String name) {
- return _wb.getNames(name);
- }
-
- /**
- * Returns all defined names
- *
- * @return all defined names
- */
- @Override
- public List<? extends Name> getAllNames()
- {
- return _wb.getAllNames();
- }
-
- /**
- * Creates a new (uninitialised) defined name in this workbook
- *
- * @return new defined name object
- */
- @Override
- public Name createName()
- {
- return _wb.createName();
- }
-
- /**
- * Remove the given defined name
- *
- * @param name the name to remove
- */
- @Override
- public void removeName(Name name)
- {
- _wb.removeName(name);
- }
-
- /**
- * Sets the printarea for the sheet provided
- * <p>
- * i.e. Reference = $A$1:$B$2
- * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
- * @param reference Valid name Reference for the Print Area
- */
- @Override
- public void setPrintArea(int sheetIndex, String reference)
- {
- _wb.setPrintArea(sheetIndex,reference);
- }
-
- /**
- * For the Convenience of Java Programmers maintaining pointers.
- * @see #setPrintArea(int, String)
- * @param sheetIndex Zero-based sheet index (0 = First Sheet)
- * @param startColumn Column to begin printarea
- * @param endColumn Column to end the printarea
- * @param startRow Row to begin the printarea
- * @param endRow Row to end the printarea
- */
- @Override
- public void setPrintArea(int sheetIndex, int startColumn, int endColumn, int startRow, int endRow)
- {
- _wb.setPrintArea(sheetIndex, startColumn, endColumn, startRow, endRow);
- }
-
- /**
- * Retrieves the reference for the printarea of the specified sheet,
- * the sheet name is appended to the reference even if it was not specified.
- *
- * @param sheetIndex Zero-based sheet index (0 Represents the first sheet to keep consistent with java)
- * @return String Null if no print area has been defined
- */
- @Override
- public String getPrintArea(int sheetIndex)
- {
- return _wb.getPrintArea(sheetIndex);
- }
-
- /**
- * Delete the printarea for the sheet specified
- *
- * @param sheetIndex Zero-based sheet index (0 = First Sheet)
- */
- @Override
- public void removePrintArea(int sheetIndex)
- {
- _wb.removePrintArea(sheetIndex);
- }
-
- /**
- * Retrieves the current policy on what to do when
- * getting missing or blank cells from a row.
- * <p>
- * The default is to return blank and null cells.
- * {@link MissingCellPolicy}
- * </p>
- */
- @Override
- public MissingCellPolicy getMissingCellPolicy()
- {
- return _wb.getMissingCellPolicy();
- }
-
- /**
- * Sets the policy on what to do when
- * getting missing or blank cells from a row.
- *
- * This will then apply to all calls to
- * {@link Row#getCell(int)}. See
- * {@link MissingCellPolicy}
- */
- @Override
- public void setMissingCellPolicy(MissingCellPolicy missingCellPolicy)
- {
- _wb.setMissingCellPolicy(missingCellPolicy);
- }
-
- /**
- * Returns the instance of DataFormat for this workbook.
- *
- * @return the DataFormat object
- */
- @Override
- public DataFormat createDataFormat()
- {
- return _wb.createDataFormat();
- }
-
- /**
- * Adds a picture to the workbook.
- *
- * @param pictureData The bytes of the picture
- * @param format The format of the picture.
- *
- * @return the index to this picture (1 based).
- * @see #PICTURE_TYPE_EMF
- * @see #PICTURE_TYPE_WMF
- * @see #PICTURE_TYPE_PICT
- * @see #PICTURE_TYPE_JPEG
- * @see #PICTURE_TYPE_PNG
- * @see #PICTURE_TYPE_DIB
- */
- @Override
- public int addPicture(byte[] pictureData, int format)
- {
- return _wb.addPicture(pictureData,format);
- }
-
- /**
- * Gets all pictures from the Workbook.
- *
- * @return the list of pictures (a list of {@link PictureData} objects.)
- */
- @Override
- public List<? extends PictureData> getAllPictures()
- {
- return _wb.getAllPictures();
- }
-
- /**
- * Returns an object that handles instantiating concrete
- * classes of the various instances one needs for HSSF, XSSF
- * and SXSSF.
- */
- @Override
- public CreationHelper getCreationHelper() {
- return new SXSSFCreationHelper(this);
- }
-
- protected boolean isDate1904() {
- return _wb.isDate1904();
- }
-
- @Override
- @NotImplemented("XSSFWorkbook#isHidden is not implemented")
- public boolean isHidden()
- {
- return _wb.isHidden();
- }
-
- @Override
- @NotImplemented("XSSFWorkbook#setHidden is not implemented")
- public void setHidden(boolean hiddenFlag)
- {
- _wb.setHidden(hiddenFlag);
- }
-
- @Override
- public boolean isSheetHidden(int sheetIx)
- {
- return _wb.isSheetHidden(sheetIx);
- }
-
- @Override
- public boolean isSheetVeryHidden(int sheetIx)
- {
- return _wb.isSheetVeryHidden(sheetIx);
- }
-
- @Override
- public SheetVisibility getSheetVisibility(int sheetIx) {
- return _wb.getSheetVisibility(sheetIx);
- }
-
- @Override
- public void setSheetHidden(int sheetIx, boolean hidden)
- {
- _wb.setSheetHidden(sheetIx,hidden);
- }
-
- @Override
- 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
- * file, for workbooks not already referenced.
- *
- * Note: this is not implemented and thus currently throws an Exception stating this.
- *
- * @param name The name the workbook will be referenced as in formulas
- * @param workbook The open workbook to fetch the link required information from
- *
- * @throws RuntimeException stating that this method is not implemented yet.
- */
- @Override
- @NotImplemented
- public int linkExternalWorkbook(String name, Workbook workbook) {
- throw new RuntimeException("Not Implemented");
- }
-
- /**
- * Register a new toolpack in this workbook.
- *
- * @param toolpack the toolpack to register
- */
- @Override
- public void addToolPack(UDFFinder toolpack)
- {
- _wb.addToolPack(toolpack);
- }
-
- /**
- * Whether the application shall perform a full recalculation when the workbook is opened.
- * <p>
- * Typically you want to force formula recalculation when you modify cell formulas or values
- * of a workbook previously created by Excel. When set to 0, this flag will tell Excel
- * that it needs to recalculate all formulas in the workbook the next time the file is opened.
- * </p>
- *
- * @param value true if the application will perform a full recalculation of
- * workbook values when the workbook is opened
- * @since 3.8
- */
- @Override
- public void setForceFormulaRecalculation(boolean value){
- _wb.setForceFormulaRecalculation(value);
- }
-
- /**
- * Whether Excel will be asked to recalculate all formulas when the workbook is opened.
- */
- @Override
- public boolean getForceFormulaRecalculation(){
- return _wb.getForceFormulaRecalculation();
- }
-
- /**
- * Returns the spreadsheet version (EXCLE2007) of this workbook
- *
- * @return EXCEL2007 SpreadsheetVersion enum
- * @since 3.14 beta 2
- */
- @Override
- public SpreadsheetVersion getSpreadsheetVersion() {
- return SpreadsheetVersion.EXCEL2007;
- }
-
- @Override
- public int addOlePackage(byte[] oleData, String label, String fileName, String command) throws IOException {
- return _wb.addOlePackage(oleData, label, fileName, command);
- }
-
-
- @Override
- public EvaluationWorkbook createEvaluationWorkbook() {
- return SXSSFEvaluationWorkbook.create(this);
- }
- }
|