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