今天遇到了一个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 }
|