]> source.dussan.org Git - poi.git/commitdiff
Patch 51634 - support SXSSF streaming from templates
authorYegor Kozlov <yegor@apache.org>
Thu, 11 Aug 2011 08:54:11 +0000 (08:54 +0000)
committerYegor Kozlov <yegor@apache.org>
Thu, 11 Aug 2011 08:54:11 +0000 (08:54 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1156544 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/status.xml
src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java
src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFWorkbook.java
src/ooxml/testcases/org/apache/poi/xssf/SXSSFITestDataProvider.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/streaming/TestSXSSFWorkbook.java

index bea5040855532c99b5fa24b8f3716f15102fc477..b1790bf74cd3bfab610ef3c34a74ac51368d4bf8 100644 (file)
@@ -34,6 +34,7 @@
 
     <changes>
         <release version="3.8-beta4" date="2011-??-??">
+           <action dev="poi-developers" type="add">51634 - support SXSSF streaming from templates</action>
            <action dev="poi-developers" type="add">initial support for XSLF usermodel API</action>
            <action dev="poi-developers" type="fix">51187 - fixed OPCPackage to correctly handle self references</action>
            <action dev="poi-developers" type="fix">51635 - Improved performance of XSSFSheet#write</action>
index d3b62a5b65797cf87d2aa116cd55a629dd89951a..8c1b9986410ef79bc4a4aedb5240adb55f383f63 100644 (file)
@@ -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 "<sheetData>" 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("<sheetData>\n");
         }
         public int getNumberOfFlushedRows()
         {
@@ -1306,7 +1306,6 @@ public class SXSSFSheet implements Sheet, Cloneable
         }
         public InputStream getWorksheetXMLInputStream() throws IOException
         {
-            _out.write("</sheetData>");
             _out.flush();
             _out.close();
             return new FileInputStream(_fd);
index 6ba4137b542f60a64d59893153db63b6155a8ef7..adcc995ec6bb824a637b8faa71978a3c4a3c4b50 100644 (file)
@@ -59,25 +59,67 @@ public class SXSSFWorkbook implements Workbook
      */
     public static final int DEFAULT_WINDOW_SIZE = 100;
 
-    XSSFWorkbook _wb=new XSSFWorkbook();
+    XSSFWorkbook _wb;
 
     HashMap<SXSSFSheet,XSSFSheet> _sxFromXHash=new HashMap<SXSSFSheet,XSSFSheet>();
     HashMap<XSSFSheet,SXSSFSheet> _xFromSxHash=new HashMap<XSSFSheet,SXSSFSheet>();
 
-    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.
+     * <p>
+     * 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.
+     * </p>
+     * <p>
+     * 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.
+     * <p>
+     * <p></p>
+     * A value of 0 is not allowed because it would flush any newly created row
+     * without having a chance to specify any cells.
+     * </p>
+     *
+     * @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.
      * <p>
      * 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.
      * </p>
@@ -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="<sheetData/>";
+        String s="<sheetData";
         int n=s.length();
-//Copy from "in" to "out" up to the string "<sheetData/>" (excluding).
+//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) break;
+                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
             {
@@ -198,8 +304,15 @@ public class SXSSFWorkbook implements Workbook
             }
         }
         outWriter.flush();
+        if (needsStartTag)
+        {
+               outWriter.write("<sheetData>\n");
+               outWriter.flush();
+        }
 //Copy the worksheet data to "out".
         copyStream(worksheetData,out);
+        outWriter.write("</sheetData>");
+        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();
index 50e1fdb686407f4feb0fed325b49f2d16ec4cec2..d5d7026b7a1e47355c1fa210361c327cd1722d57 100755 (executable)
@@ -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) {
index a1ef9c1bdf938f94f8181e96dd65b56c0997cb61..c8b5b61787219c9dc03cf980515636d00b1fa104 100755 (executable)
 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());
+    }
 }