From: Yegor Kozlov Date: Thu, 11 Aug 2011 08:54:11 +0000 (+0000) Subject: Patch 51634 - support SXSSF streaming from templates X-Git-Tag: REL_3_8_BETA4~13 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=453e72046dfcee0a9dbfd3b6202dbc0dd022f6b3;p=poi.git Patch 51634 - support SXSSF streaming from templates git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1156544 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index bea5040855..b1790bf74c 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + 51634 - support SXSSF streaming from templates initial support for XSLF usermodel API 51187 - fixed OPCPackage to correctly handle self references 51635 - Improved performance of XSSFSheet#write diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index d3b62a5b65..8c1b998641 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -44,11 +44,12 @@ public class SXSSFSheet implements Sheet, Cloneable SheetDataWriter _writer; int _randomAccessWindowSize = SXSSFWorkbook.DEFAULT_WINDOW_SIZE; - public SXSSFSheet(SXSSFWorkbook workbook,XSSFSheet xSheet) throws IOException + public SXSSFSheet(SXSSFWorkbook workbook, XSSFSheet xSheet) throws IOException { - _workbook=workbook; - _sh=xSheet; + _workbook=workbook; + _sh=xSheet; _writer=new SheetDataWriter(); + setRandomAccessWindowSize(_workbook.getRandomAccessWindowSize()); } /* Gets "" document fragment*/ @@ -1286,7 +1287,6 @@ public class SXSSFSheet implements Sheet, Cloneable _fd = File.createTempFile("poi-sxxsf-sheet", ".xml"); _fd.deleteOnExit(); _out = new BufferedWriter(new FileWriter(_fd)); - _out.write("\n"); } public int getNumberOfFlushedRows() { @@ -1306,7 +1306,6 @@ public class SXSSFSheet implements Sheet, Cloneable } public InputStream getWorksheetXMLInputStream() throws IOException { - _out.write(""); _out.flush(); _out.close(); return new FileInputStream(_fd); diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java index 6ba4137b54..adcc995ec6 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java @@ -59,25 +59,67 @@ public class SXSSFWorkbook implements Workbook */ public static final int DEFAULT_WINDOW_SIZE = 100; - XSSFWorkbook _wb=new XSSFWorkbook(); + XSSFWorkbook _wb; HashMap _sxFromXHash=new HashMap(); HashMap _xFromSxHash=new HashMap(); - int _randomAccessWindowSize = DEFAULT_WINDOW_SIZE; + private int _randomAccessWindowSize = DEFAULT_WINDOW_SIZE; /** * Construct a new workbook */ public SXSSFWorkbook(){ + this(null /*workbook*/); + } + + public SXSSFWorkbook(XSSFWorkbook workbook){ + this(workbook, DEFAULT_WINDOW_SIZE); + } + + /** + * Constructs an workbook from an existing workbook. + *

+ * When a new node is created via 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 getRow() anymore. + *

+ *

+ * A value of -1 indicates unlimited access. In this case all + * records that have not been flushed by a call to flush() are available + * for random access. + *

+ *

+ * A value of 0 is not allowed because it would flush any newly created row + * without having a chance to specify any cells. + *

+ * + * @param rowAccessWindowSize + */ + public SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize){ + setRandomAccessWindowSize(rowAccessWindowSize); + if (workbook == null) + { + _wb=new XSSFWorkbook(); + } + else + { + _wb=workbook; + for ( int i = 0; i < _wb.getNumberOfSheets(); i++ ) + { + XSSFSheet sheet = _wb.getSheetAt( i ); + createAndRegisterSXSSFSheet( sheet ); + } + } } /** * Construct an empty workbook and specify the window for row access. *

* When a new node is created via createRow() and the total number - * of unflushed records would exeed the specified value, then the + * of unflushed records would exceed the specified value, then the * row with the lowest index value is flushed and cannot be accessed * via getRow() anymore. *

@@ -94,6 +136,15 @@ public class SXSSFWorkbook implements Workbook * @param rowAccessWindowSize */ public SXSSFWorkbook(int rowAccessWindowSize){ + this(null /*workbook*/, rowAccessWindowSize); + } + + public int getRandomAccessWindowSize() + { + return _randomAccessWindowSize; + } + private void setRandomAccessWindowSize(int rowAccessWindowSize) + { if(rowAccessWindowSize == 0 || rowAccessWindowSize < -1) { throw new IllegalArgumentException("rowAccessWindowSize must be greater than 0 or -1"); } @@ -168,20 +219,75 @@ public class SXSSFWorkbook implements Workbook out.write(chunk,0,count); } } - private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out,InputStream worksheetData) throws IOException { + private static void copyStreamAndInjectWorksheet(InputStream in, OutputStream out, InputStream worksheetData) throws IOException { InputStreamReader inReader=new InputStreamReader(in,"UTF-8"); //TODO: Is it always UTF-8 or do we need to read the xml encoding declaration in the file? If not, we should perhaps use a SAX reader instead. OutputStreamWriter outWriter=new OutputStreamWriter(out,"UTF-8"); + boolean needsStartTag = true; int c; int pos=0; - String s=""; + String s="" (excluding). +//Copy from "in" to "out" up to the string "" or "" (excluding). while(((c=inReader.read())!=-1)) { if(c==s.charAt(pos)) { pos++; - if(pos==n) break; + if(pos==n) + { + if ("') + { + // Found + outWriter.write(s); + outWriter.write(c); + s = ""; + n = s.length(); + pos = 0; + needsStartTag = false; + continue; + } + if (c == '/') + { + // Found ') + { + // Found + 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 + break; + } + } } else { @@ -198,8 +304,15 @@ public class SXSSFWorkbook implements Workbook } } outWriter.flush(); + if (needsStartTag) + { + outWriter.write("\n"); + outWriter.flush(); + } //Copy the worksheet data to "out". copyStream(worksheetData,out); + outWriter.write(""); + outWriter.flush(); //Copy the rest of "in" to "out". while(((c=inReader.read())!=-1)) outWriter.write(c); @@ -348,7 +461,6 @@ public class SXSSFWorkbook implements Workbook { throw new RuntimeException(ioe); } - sxSheet.setRandomAccessWindowSize(_randomAccessWindowSize); registerSheetMapping(sxSheet,xSheet); return sxSheet; } @@ -532,6 +644,11 @@ public class SXSSFWorkbook implements Workbook */ public void write(OutputStream stream) throws IOException { + for (SXSSFSheet sheet : _xFromSxHash.values()) + { + sheet.flushRows(); + } + //Save the template File tmplFile = File.createTempFile("poi-sxxsf-template", ".xlsx"); tmplFile.deleteOnExit(); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/SXSSFITestDataProvider.java b/src/ooxml/testcases/org/apache/poi/xssf/SXSSFITestDataProvider.java index 50e1fdb686..d5d7026b7a 100755 --- a/src/ooxml/testcases/org/apache/poi/xssf/SXSSFITestDataProvider.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/SXSSFITestDataProvider.java @@ -20,7 +20,6 @@ package org.apache.poi.xssf; import org.apache.poi.POIDataSamples; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.ITestDataProvider; import org.apache.poi.ss.SpreadsheetVersion; import org.apache.poi.ss.usermodel.Workbook; @@ -42,7 +41,8 @@ public final class SXSSFITestDataProvider implements ITestDataProvider { // enforce singleton } public Workbook openSampleWorkbook(String sampleFileName) { - throw new IllegalArgumentException("SXSSF cannot read files"); + XSSFWorkbook xssfWorkbook = XSSFITestDataProvider.instance.openSampleWorkbook(sampleFileName); + return new SXSSFWorkbook(xssfWorkbook); } public Workbook writeOutAndReadBack(Workbook wb) { diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/streaming/TestSXSSFWorkbook.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/streaming/TestSXSSFWorkbook.java index a1ef9c1bdf..c8b5b61787 100755 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/streaming/TestSXSSFWorkbook.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/streaming/TestSXSSFWorkbook.java @@ -20,7 +20,12 @@ package org.apache.poi.xssf.usermodel.streaming; import org.apache.poi.ss.usermodel.BaseTestWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.SXSSFITestDataProvider; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; public final class TestSXSSFWorkbook extends BaseTestWorkbook { @@ -55,5 +60,81 @@ public final class TestSXSSFWorkbook extends BaseTestWorkbook { "Only XSSFCells can be evaluated.", e.getMessage()); } } - + + public void testExistingWorkbook() { + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(); + xssfWorkbook.createSheet("S1"); + SXSSFWorkbook wb = new SXSSFWorkbook(xssfWorkbook); + xssfWorkbook = (XSSFWorkbook) SXSSFITestDataProvider.instance.writeOutAndReadBack(wb); + wb = new SXSSFWorkbook(xssfWorkbook); + assertEquals(1, wb.getNumberOfSheets()); + Sheet sheet = wb.getSheetAt(0); + assertNotNull(sheet); + assertEquals("S1", sheet.getSheetName()); + } + + public void testAddToExistingWorkbook() { + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(); + xssfWorkbook.createSheet("S1"); + Sheet sheet = xssfWorkbook.createSheet("S2"); + Row row = sheet.createRow(1); + Cell cell = row.createCell(1); + cell.setCellValue("value 2_1_1"); + SXSSFWorkbook wb = new SXSSFWorkbook(xssfWorkbook); + xssfWorkbook = (XSSFWorkbook) SXSSFITestDataProvider.instance.writeOutAndReadBack(wb); + wb = new SXSSFWorkbook(xssfWorkbook); + + // Add a row to the existing empty sheet + Sheet sheet1 = wb.getSheetAt(0); + Row row1_1 = sheet1.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 + Sheet sheet2 = wb.getSheetAt(1); + Row row2_2 = sheet2.createRow(2); + Cell cell2_2_1 = row2_2.createCell(1); + cell2_2_1.setCellValue("value 2_2_1"); + + // Add a sheet with one row + Sheet sheet3 = wb.createSheet("S3"); + Row row3_1 = sheet3.createRow(1); + Cell cell3_1_1 = row3_1.createCell(1); + cell3_1_1.setCellValue("value 3_1_1"); + + xssfWorkbook = (XSSFWorkbook) SXSSFITestDataProvider.instance.writeOutAndReadBack(wb); + assertEquals(3, xssfWorkbook.getNumberOfSheets()); + // Verify sheet 1 + sheet1 = xssfWorkbook.getSheetAt(0); + assertEquals("S1", sheet1.getSheetName()); + assertEquals(1, sheet1.getPhysicalNumberOfRows()); + row1_1 = sheet1.getRow(1); + assertNotNull(row1_1); + cell1_1_1 = row1_1.getCell(1); + assertNotNull(cell1_1_1); + assertEquals("value 1_1_1", cell1_1_1.getStringCellValue()); + // Verify sheet 2 + sheet2 = xssfWorkbook.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()); + row2_2 = sheet2.getRow(2); + assertNotNull(row2_2); + cell2_2_1 = row2_2.getCell(1); + assertNotNull(cell2_2_1); + assertEquals("value 2_2_1", cell2_2_1.getStringCellValue()); + // Verify sheet 3 + sheet3 = xssfWorkbook.getSheetAt(2); + assertEquals("S3", sheet3.getSheetName()); + assertEquals(1, sheet3.getPhysicalNumberOfRows()); + row3_1 = sheet3.getRow(1); + assertNotNull(row3_1); + cell3_1_1 = row3_1.getCell(1); + assertNotNull(cell3_1_1); + assertEquals("value 3_1_1", cell3_1_1.getStringCellValue()); + } }