关于poi导出大数据量EXCEL导出缓慢的解决方案--生成xml格式的表格文件(注意xls格式为03 07下格式会不一样)


今天遇到了一个POI导出EXCEL文件结果文件大小太大导致系统运行缓慢的问题。想到了使用输出XML格式的表格来完成。

首先,我们需要理解一下为什么POI导出EXCEL文件会导致文件大小变大。最主要的原因应该是POI变成中经常会对无关的单元格设置属性。例如:一个EXCEL工作表的最大列数为256,我们只使用10列。而编程时经常会将256列全部渲染格式,造成很大的资源浪费。当然应该还有其他很多原因也会造成表格变大。

使用这个方案的前提是对于表格的格式要求不高,因为使用的是自己的工具,没有POI优化了那么多格式。

接下来我们看一下这个方法的理论依据:

我们新建一个aa.xls。内容就少一点,方便观察。内容如下:

使用文件--》另存为--》.xml 得到一个 aa.xml。

<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet" xmlns:html="http://www.w3.org/TR/REC-html40">
 <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
  <Created>1996-12-17T01:32:42Z</Created>
  <LastSaved>2015-03-04T02:45:33Z</LastSaved>
  <Version>11.9999</Version>
 </DocumentProperties>
 <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
  <RemovePersonalInformation/>
 </OfficeDocumentSettings>
 <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
  <WindowHeight>4530</WindowHeight>
  <WindowWidth>8505</WindowWidth>
  <WindowTopX>480</WindowTopX>
  <WindowTopY>120</WindowTopY>
  <AcceptLabelsInFormulas/>
  <ProtectStructure>False</ProtectStructure>
  <ProtectWindows>False</ProtectWindows>
 </ExcelWorkbook>
 <Styles> <Style ss:ID="Default" ss:Name="Normal"> <Alignment ss:Vertical="Bottom"/> <Borders/> <Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/> <Interior/> <NumberFormat/> <Protection/> </Style>
  <Style ss:ID="s21"> <Font ss:FontName="宋体" x:CharSet="134" ss:Size="12" ss:Bold="1"/> </Style>
 </Styles>
 <Worksheet ss:Name="Sheet1">
  <Table ss:ExpandedColumnCount="5" ss:ExpandedRowCount="12" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25">
   <Row>
    <Cell ss:StyleID="s21"><Data ss:Type="String">A</Data></Cell>
    <Cell ss:StyleID="s21"><Data ss:Type="String">B</Data></Cell>
    <Cell ss:StyleID="s21"><Data ss:Type="String">C</Data></Cell>
    <Cell ss:StyleID="s21"><Data ss:Type="String">D</Data></Cell>
    <Cell ss:StyleID="s21"><Data ss:Type="String">E</Data></Cell>
   </Row>
   <Row ss:Index="4">
    <Cell ss:Index="2"><Data ss:Type="String">aaa</Data></Cell>
   </Row>
   <Row ss:Index="8">
    <Cell ss:Index="4"><Data ss:Type="String">ddd</Data></Cell>
   </Row>
   <Row>
    <Cell ss:Index="2"><Data ss:Type="String">sss</Data></Cell>
   </Row>
   <Row ss:Index="11">
    <Cell><Data ss:Type="String">fddd</Data></Cell>
   </Row>
   <Row>
    <Cell ss:Index="4"><Data ss:Type="String">fff</Data></Cell>
   </Row>
  </Table>
  <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
   <Print>
    <ValidPrinterInfo/>
    <PaperSizeIndex>9</PaperSizeIndex>
    <HorizontalResolution>200</HorizontalResolution>
    <VerticalResolution>200</VerticalResolution>
   </Print>
   <Selected/>
   <Panes>
    <Pane>
     <Number>3</Number>
     <RangeSelection>R1C1:R12C5</RangeSelection>
    </Pane>
   </Panes>
   <ProtectObjects>False</ProtectObjects>
   <ProtectScenarios>False</ProtectScenarios>
  </WorksheetOptions>
 </Worksheet>
 <Worksheet ss:Name="Sheet2">
  <Table ss:ExpandedColumnCount="0" ss:ExpandedRowCount="0" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25"/>
  <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
   <ProtectObjects>False</ProtectObjects>
   <ProtectScenarios>False</ProtectScenarios>
  </WorksheetOptions>
 </Worksheet>
 <Worksheet ss:Name="Sheet3">
  <Table ss:ExpandedColumnCount="0" ss:ExpandedRowCount="0" x:FullColumns="1" x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25"/>
  <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
   <ProtectObjects>False</ProtectObjects>
   <ProtectScenarios>False</ProtectScenarios>
  </WorksheetOptions>
 </Worksheet>
</Workbook>

 

可以看到 其实输出文件就是一个标准的xml文档。而且该文档还有一个很特殊的地方就是:文档的后缀名一旦修改为.XLS那么直接就可以生成一个表格文件。所以,如果我们找到XML的对应关系就可以通过输出XML文件,重命名为.XLS文件。完成减小EXCEL大小的目的。

最后贴上一个测试的类 TEST.java 完成了基本对应关系。但是还有很多需要摸索的地方:例如格式,函数。希望对大家有所帮助。

  

 1 package com.sun;  2 import java.io.BufferedWriter;  3 import java.io.File;  4 import java.io.FileNotFoundException;  5 import java.io.FileOutputStream;  6 import java.io.IOException;  7 import java.io.OutputStreamWriter;  8 
 9 
 10 public class Test {  11      public static void main(String[] args) {  12             StringBuffer sb = new StringBuffer();  13             try {  14                 OutputStreamWriter write = new OutputStreamWriter(new FileOutputStream(new File("d://aa.xls")),"UTF-8");  15                   BufferedWriter output = new BufferedWriter(write);  16                 sb.append("<?xml version=\"1.0\"?>");  17                 sb.append("\n");  18                 sb.append("<?mso-application progid=\"Excel.Sheet\"?>");  19                 sb.append("\n");  20                 sb.append("<Workbook xmlns=\"urn:schemas-microsoft-com:office:spreadsheet\"");  21                 sb.append("\n");  22                 sb.append("  xmlns:o=\"urn:schemas-microsoft-com:office:office\"");  23                 sb.append("\n");  24                 sb.append(" xmlns:x=\"urn:schemas-microsoft-com:office:excel\"");  25                 sb.append("\n");  26                 sb.append(" xmlns:ss=\"urn:schemas-microsoft-com:office:spreadsheet\"");  27                 sb.append("\n");  28                 sb.append(" xmlns:html=\"http://www.w3.org/TR/REC-html40\">");  29                 sb.append("\n");  30                 sb.append(" <Styles>\n");  31                 sb.append("  <Style ss:ID=\"Default\" ss:Name=\"Normal\">\n");  32                 sb.append("   <Alignment ss:Vertical=\"Center\"/>\n");  33                 sb.append("   <Borders/>\n");  34                 sb.append("   <Font ss:FontName=\"宋体\" x:CharSet=\"134\" ss:Size=\"12\"/>\n");  35                 sb.append("   <Interior/>\n");  36                 sb.append("   <NumberFormat/>\n");  37                 sb.append("   <Protection/>\n");  38                 sb.append("  </Style>\n");  39                 sb.append(" </Styles>\n");  40                 //行数
 41                 int rowNum = 20;  42                 
 43                 int currentRecord = 0;  44                 //总数据量
 45                 int total = 2000;  46                 //列数
 47                 int columnNum = 10;  48                 //第一个工作表 
 49                 sb.append("<Worksheet ss:Name=\"Sheet0\">");  50                 sb.append("\n");  51                 sb.append("<Table ss:ExpandedColumnCount=\"" + columnNum  52                         + "\" ss:ExpandedRowCount=\"" + rowNum  53                         + "\" x:FullColumns=\"1\" x:FullRows=\"1\">");  54                 sb.append("\n");  55                 for (int i = 0; i < total; i++) {  56                     if ((currentRecord == rowNum  57                             || currentRecord > rowNum || currentRecord == 0)  58                             && i != 0) {// 一个sheet写满 
 59                         currentRecord = 0;  60  output.write(sb.toString());  61                         sb.setLength(0);  62                         sb.append("</Table>");  63                         sb.append("<WorksheetOptions xmlns=\"urn:schemas-microsoft-com:office:excel\">");  64                         sb.append("\n");  65                         sb.append("<ProtectObjects>False</ProtectObjects>");  66                         sb.append("\n");  67                         sb.append("<ProtectScenarios>False</ProtectScenarios>");  68                         sb.append("\n");  69                         sb.append("</WorksheetOptions>");  70                         sb.append("\n");  71                         sb.append("</Worksheet>");  72                         sb.append("<Worksheet ss:Name=\"Sheet" + i / rowNum  73                                 + "\">");  74                         sb.append("\n");  75                         sb.append("<Table ss:ExpandedColumnCount=\"" + columnNum  76                                 + "\" ss:ExpandedRowCount=\"" + rowNum  77                                 + "\" x:FullColumns=\"1\" x:FullRows=\"1\">");  78                         sb.append("\n");  79  }  80                     sb.append("<Row>");  81                     for (int j = 0; j < columnNum; j++) {  82                         sb.append("<Cell><Data ss:Type=\"String\">第"+(i+1)+"列第"+(j+1)+"行</Data></Cell>");  83                         sb.append("\n");  84  }  85                     sb.append("</Row>");  86                     //每三百行数据批量提交一次
 87                     if (i % 300 == 0) {  88                         System.out.println("提交了");  89  output.write(sb.toString());  90  output.flush();  91                         sb.setLength(0);  92  }  93                     sb.append("\n");  94                     currentRecord++;  95  }  96  output.write(sb.toString());  97                 sb.setLength(0);  98                 sb.append("</Table>");  99                 sb.append("<WorksheetOptions xmlns=\"urn:schemas-microsoft-com:office:excel\">"); 100                 sb.append("\n"); 101                 sb.append("<ProtectObjects>False</ProtectObjects>"); 102                 sb.append("\n"); 103                 sb.append("<ProtectScenarios>False</ProtectScenarios>"); 104                 sb.append("\n"); 105                 sb.append("</WorksheetOptions>"); 106                 sb.append("\n"); 107                 sb.append("</Worksheet>"); 108                 sb.append("</Workbook>"); 109                 sb.append("\n"); 110  output.write(sb.toString()); 111  output.flush(); 112  output.close(); 113             } catch (FileNotFoundException e) { 114  e.printStackTrace(); 115             } catch (IOException e) { 116  e.printStackTrace(); 117  } 118  } 119 }

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM