Java 使用stringTemplate导出大批量数据excel(百万级)

摘要:
目前java框架中能够生成excel文件的的确不少,但是,能够生成大数据量的excel框架,我倒是没发现,一般数据量大了都会出现内存溢出,所以,生成大数据量的excel文件要返璞归真,用java的基础技术,IO流来实现。同理,excel文件也是可以的。把下面的xml字符串复制到文本文件,然后保存为xls格式,就是一个excel文件。

目前java框架中能够生成excel文件的的确不少,但是,能够生成大数据量的excel框架,我倒是没发现,一般数据量大了都会出现内存溢出,所以,生成大数据量的excel文件要返璞归真,用java的基础技术,IO流来实现。 如果想用IO流来生成excel文件,必须要知道excel的文件格式内容,相当于生成html文件一样,用字符串拼接html标签保存到文本文件就可以生成一个html文件了。同理,excel文件也是可以的。怎么知道excel的文件格式呢?其实很简单,随便新建一个excel文件,双击打开,然后点击“文件”-》“另存为”,保存的类型为“xml表格”,保存之后用文本格式打开,就可以看到excel的字符串格式一览无遗了。
把下面的xml字符串复制到文本文件,然后保存为xls格式,就是一个excel文件。

  1. <?xmlversion="1.0"?>
  2. <?mso-applicationprogid="Excel.Sheet"?>
  3. <Workbookxmlns="urn:schemas-microsoft-com:office:spreadsheet"
  4. xmlns:o="urn:schemas-microsoft-com:office:office"
  5. xmlns:x="urn:schemas-microsoft-com:office:excel"
  6. xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  7. xmlns:html="http://www.w3.org/TR/REC-html40">
  8. <DocumentPropertiesxmlns="urn:schemas-microsoft-com:office:office">
  9. <Created>1996-12-17T01:32:42Z</Created>
  10. <LastSaved>2000-11-18T06:53:49Z</LastSaved>
  11. <Version>11.9999</Version>
  12. </DocumentProperties>
  13. <OfficeDocumentSettingsxmlns="urn:schemas-microsoft-com:office:office">
  14. <RemovePersonalInformation/>
  15. </OfficeDocumentSettings>
  16. <ExcelWorkbookxmlns="urn:schemas-microsoft-com:office:excel">
  17. <WindowHeight>4530</WindowHeight>
  18. <WindowWidth>8505</WindowWidth>
  19. <WindowTopX>480</WindowTopX>
  20. <WindowTopY>120</WindowTopY>
  21. <AcceptLabelsInFormulas/>
  22. <ProtectStructure>False</ProtectStructure>
  23. <ProtectWindows>False</ProtectWindows>
  24. </ExcelWorkbook>
  25. <Styles>
  26. <Styless:ID="Default"ss:Name="Normal">
  27. <Alignmentss:Vertical="Bottom"/>
  28. <Borders/>
  29. <Fontss:FontName="宋体"x:CharSet="134"ss:Size="12"/>
  30. <Interior/>
  31. <NumberFormat/>
  32. <Protection/>
  33. </Style>
  34. </Styles>
  35. <Worksheetss:Name="Sheet1">
  36. <Tabless:ExpandedColumnCount="2"ss:ExpandedRowCount="2"x:FullColumns="1"
  37. x:FullRows="1"ss:DefaultColumnWidth="54"ss:DefaultRowHeight="14.25">
  38. <Columnss:AutoFitWidth="0"ss:Width="73.5"/>
  39. <Row>
  40. <Cell><Datass:Type="String">zhangzehao</Data></Cell>
  41. <Cell><Datass:Type="String">zhangzehao</Data></Cell>
  42. </Row>
  43. <Row>
  44. <Cell><Datass:Type="String">zhangzehao</Data></Cell>
  45. </Row>
  46. </Table>
  47. <WorksheetOptionsxmlns="urn:schemas-microsoft-com:office:excel">
  48. <Selected/>
  49. <Panes>
  50. <Pane>
  51. <Number>3</Number>
  52. <ActiveRow>5</ActiveRow>
  53. <ActiveCol>3</ActiveCol>
  54. </Pane>
  55. </Panes>
  56. <ProtectObjects>False</ProtectObjects>
  57. <ProtectScenarios>False</ProtectScenarios>
  58. </WorksheetOptions>
  59. </Worksheet>
  60. <Worksheetss:Name="Sheet2">
  61. <Tabless:ExpandedColumnCount="0"ss:ExpandedRowCount="0"x:FullColumns="1"
  62. x:FullRows="1"ss:DefaultColumnWidth="54"ss:DefaultRowHeight="14.25"/>
  63. <WorksheetOptionsxmlns="urn:schemas-microsoft-com:office:excel">
  64. <ProtectObjects>False</ProtectObjects>
  65. <ProtectScenarios>False</ProtectScenarios>
  66. </WorksheetOptions>
  67. </Worksheet>
  68. <Worksheetss:Name="Sheet3">
  69. <Tabless:ExpandedColumnCount="0"ss:ExpandedRowCount="0"x:FullColumns="1"
  70. x:FullRows="1"ss:DefaultColumnWidth="54"ss:DefaultRowHeight="14.25"/>
  71. <WorksheetOptionsxmlns="urn:schemas-microsoft-com:office:excel">
  72. <ProtectObjects>False</ProtectObjects>
  73. <ProtectScenarios>False</ProtectScenarios>
  74. </WorksheetOptions>
  75. </Worksheet>
  76. </Workbook>
<?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>2000-11-18T06:53:49Z</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:  ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
</Styles>
<Worksheet ss:Name="Sheet1">
  <Table ss:ExpandedColumnCount="2" ss:ExpandedRowCount="2" x:FullColumns="1"
   x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25">
   <Column ss:AutoFitWidth="0" ss: />
   <Row>
    <Cell><Data ss:Type="String">zhangzehao</Data></Cell>
    <Cell><Data ss:Type="String">zhangzehao</Data></Cell>
   </Row>
   <Row>
    <Cell><Data ss:Type="String">zhangzehao</Data></Cell>
   </Row>
  </Table>
  <WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
   <Selected/>
   <Panes>
    <Pane>
     <Number>3</Number>
     <ActiveRow>5</ActiveRow>
     <ActiveCol>3</ActiveCol>
    </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>

如果要生成千万级别以上的excel,除了这个关键点之外,还要控制IO流,如果有1000万记录,要迭代1000万次组装xml字符串,这样肯定占用相当大的内存,肯定内存溢出,所以,必须把组装的xml字符串分批用IO流刷新到硬盘里,如果是在web应用中,可以刷新到response中,web应用会自动把临时流保存到客户端的临时文件中,然后再一次性复制到你保存的路径。言归正传,分批刷新的话,可以迭代一批数据就flush进硬盘,同时把list,大对象赋值为空,显式调用垃圾回收器,表明要回收内存。这样的话,不管生成多大的数据量都不会出现内存溢出的,我曾经试过导出1亿的excel文件,都不会出现内存溢出,只是用了35分钟。 当然,如果要把实现做的优雅一些,在组装xml字符串的时候,可以结合模板技术来实现,我个人喜好stringtemplate这个轻量级的框架,我给出的DEMO也是采用了模板技术生成的,当然velocity和freemarker都是可以,stringbuilder也行,呵呵。 我为人比较懒,本意不是为了写个帖子的,只是想多赚点下载豆:lol1 ,这和赚钱一样谁不想?谁知道就写了那么多。同时鄙人知识寡陋,希望可以抛砖引玉。

综上:使用技术为 stringTemplate

pom.xml:

  1. <dependency>
  2. <groupId>antlr</groupId>
  3. <artifactId>antlr</artifactId>
  4. <version>2.7.7</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.antlr</groupId>
  8. <artifactId>stringtemplate</artifactId>
  9. <version>3.2.1</version>
  10. </dependency>
<dependency>
            <groupId>antlr</groupId>
            <artifactId>antlr</artifactId>
            <version>2.7.7</version>
        </dependency>
        <dependency>
            <groupId>org.antlr</groupId>
            <artifactId>stringtemplate</artifactId>
            <version>3.2.1</version>
        </dependency>

template对象:

  1. classRow{
  2. privateList<String>result;
  3. publicList<String>getResult(){
  4. returnresult;
  5. }
  6. publicvoidsetResult(List<String>result){
  7. this.result=result;
  8. }
  9. }
  10. classWorksheet{
  11. privateStringsheet;
  12. privateintcolumnNum;
  13. privateintrowNum;
  14. privateList<String>title;
  15. privateList<Row>rows;
  16. publicStringgetSheet(){
  17. returnsheet;
  18. }
  19. publicvoidsetSheet(Stringsheet){
  20. this.sheet=sheet;
  21. }
  22. publicList<Row>getRows(){
  23. returnrows;
  24. }
  25. publicvoidsetRows(List<Row>rows){
  26. this.rows=rows;
  27. }
  28. publicintgetColumnNum(){
  29. returncolumnNum;
  30. }
  31. publicvoidsetColumnNum(intcolumnNum){
  32. this.columnNum=columnNum;
  33. }
  34. publicintgetRowNum(){
  35. returnrowNum;
  36. }
  37. publicvoidsetRowNum(introwNum){
  38. this.rowNum=rowNum;
  39. }
  40. publicList<String>getTitle(){
  41. returntitle;
  42. }
  43. publicvoidsetTitle(List<String>title){
  44. this.title=title;
  45. }
  46. }
class Row{
    private List<String> result;
    public List<String> getResult() {
        return result;
    }
    public void setResult(List<String> result) {
        this.result = result;
    }
}
class Worksheet{
	private String sheet;
	private int columnNum;
	private int rowNum;
    private List<String> title;
	private List<Row> rows;
	public String getSheet() {
		return sheet;
	}
	public void setSheet(String sheet) {
		this.sheet = sheet;
	}
	public List<Row> getRows() {
		return rows;
	}
	public void setRows(List<Row> rows) {
		this.rows = rows;
	}
	public int getColumnNum() {
		return columnNum;
	}
	public void setColumnNum(int columnNum) {
		this.columnNum = columnNum;
	}
	public int getRowNum() {
		return rowNum;
	}
	public void setRowNum(int rowNum) {
		this.rowNum = rowNum;
	}
    public List<String> getTitle() {
        return title;
    }
    public void setTitle(List<String> title) {
        this.title = title;
    }
}

模版文件(通用):

excel 头模板

  1. <?xmlversion="1.0"?>
  2. <?mso-applicationprogid="Excel.Sheet"?>
  3. <Workbookxmlns="urn:schemas-microsoft-com:office:spreadsheet"
  4. xmlns:o="urn:schemas-microsoft-com:office:office"
  5. xmlns:x="urn:schemas-microsoft-com:office:excel"
  6. xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
  7. xmlns:html="http://www.w3.org/TR/REC-html40">
  8. <DocumentPropertiesxmlns="urn:schemas-microsoft-com:office:office">
  9. <Created>1996-12-17T01:32:42Z</Created>
  10. <LastSaved>2013-08-02T09:21:24Z</LastSaved>
  11. <Version>11.9999</Version>
  12. </DocumentProperties>
  13. <OfficeDocumentSettingsxmlns="urn:schemas-microsoft-com:office:office">
  14. <RemovePersonalInformation/>
  15. </OfficeDocumentSettings>
  16. <ExcelWorkbookxmlns="urn:schemas-microsoft-com:office:excel">
  17. <WindowHeight>4530</WindowHeight>
  18. <WindowWidth>8505</WindowWidth>
  19. <WindowTopX>480</WindowTopX>
  20. <WindowTopY>120</WindowTopY>
  21. <AcceptLabelsInFormulas/>
  22. <ProtectStructure>False</ProtectStructure>
  23. <ProtectWindows>False</ProtectWindows>
  24. </ExcelWorkbook>
  25. <Styles>
  26. <Styless:ID="Default"ss:Name="Normal">
  27. <Alignmentss:Vertical="Bottom"/>
  28. <Borders/>
  29. <Fontss:FontName="宋体"x:CharSet="134"ss:Size="12"/>
  30. <Interior/>
  31. <NumberFormat/>
  32. <Protection/>
  33. </Style>
  34. </Styles>
<?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>2013-08-02T09:21:24Z</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:  ss:Name="Normal">
   <Alignment ss:Vertical="Bottom"/>
   <Borders/>
   <Font ss:FontName="宋体" x:CharSet="134" ss:Size="12"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
 </Styles>

body模板:

  1. $worksheet:{
  2. <Worksheetss:Name="$it.sheet$">
  3. <Tabless:ExpandedColumnCount="$it.columnNum$"ss:ExpandedRowCount="$it.rowNum$"x:FullColumns="1"
  4. x:FullRows="1"ss:DefaultColumnWidth="54"ss:DefaultRowHeight="14.25">
  5. <Row>
  6. $it.title:{
  7. <Cell><Datass:Type="String">$it$</Data></Cell>
  8. }$
  9. </Row>
  10. $it.rows:{
  11. <Row>
  12. $it.result:{
  13. <Cell><Datass:Type="String">$it$</Data></Cell>
  14. }$
  15. </Row>
  16. }$
  17. </Table>
  18. </Worksheet>
  19. }$
 $worksheet:{
 <Worksheet ss:Name="$it.sheet$">
  <Table ss:ExpandedColumnCount="$it.columnNum$" ss:ExpandedRowCount="$it.rowNum$" x:FullColumns="1"
   x:FullRows="1" ss:DefaultColumnWidth="54" ss:DefaultRowHeight="14.25">
   <Row>
   $it.title:{
   <Cell><Data ss:Type="String">$it$</Data></Cell>
   }$
   </Row>
 $it.rows:{
 <Row>
 $it.result:{
 <Cell><Data ss:Type="String">$it$</Data></Cell>
 }$
   </Row>
 }$
  </Table>
 </Worksheet>
}$

实际处理类:传入list对象,利用反射获取对象属性名及属性值

  1. longstartTimne=System.currentTimeMillis();
  2. StringTemplateGroupstGroup=newStringTemplateGroup("stringTemplate");
  3. //写入excel文件头部信息
  4. StringTemplatehead=stGroup.getInstanceOf("head");
  5. Filefile=newFile("D:/output2.xls");
  6. PrintWriterwriter=newPrintWriter(newBufferedOutputStream(newFileOutputStream(file)));
  7. writer.print(head.toString());
  8. writer.flush();
  9. inttotalRowNum=listWinningRecordDTOList.size();
  10. intmaxRowNum=60000;
  11. intsheets=totalRowNum%60000==0?(totalRowNum/maxRowNum):(totalRowNum/maxRowNum+1);
  12. //excel单表最大行数是65535
  13. Listrecord=listWinningRecordDTOList;
  14. List<String>title=newArrayList<String>();
  15. List<Method>getMethods=newArrayList<Method>();
  16. Class<?>clazz=record.get(0).getClass();
  17. Field[]fields=clazz.getDeclaredFields();
  18. if(fields!=null&&fields.length>0){
  19. for(Fieldfield:fields){
  20. if(!"serialVersionUID".equals(field.getName())){
  21. title.add(field.getName());
  22. getMethods.add(clazz.getDeclaredMethod("get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1)));
  23. }
  24. }
  25. }
  26. //BeanInfobeanInfo=Introspector.getBeanInfo(clazz,Object.class);
  27. //PropertyDescriptor[]proDescrtptors=beanInfo.getPropertyDescriptors();
  28. //for(PropertyDescriptorpropertyDescriptor:proDescrtptors){
  29. //title.add(propertyDescriptor.getName());
  30. //getMethods.add(propertyDescriptor.getReadMethod());
  31. //}
  32. intcolumnLength=title.size();
  33. SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  34. //写入excel文件数据信息
  35. for(inti=0;i<sheets;i++){
  36. StringTemplatebody=stGroup.getInstanceOf("body");
  37. Worksheetworksheet=newWorksheet();
  38. worksheet.setTitle(title);
  39. worksheet.setSheet(""+(i+1)+"");
  40. worksheet.setColumnNum(columnLength);
  41. worksheet.setRowNum(maxRowNum+1);
  42. List<Row>rows=newArrayList<Row>();
  43. intstartIndex=i*maxRowNum;
  44. intendIndex=Math.min((i+1)*maxRowNum-1,totalRowNum-1);
  45. for(intj=startIndex;j<=endIndex;j++){
  46. Rowrow=newRow();
  47. List<String>result=newArrayList<String>(columnLength);
  48. for(intn=0;n<columnLength;n++){
  49. Objectvalue=getMethods.get(n).invoke(record.get(j));
  50. if(value==null){
  51. result.add("");
  52. }else{
  53. if(valueinstanceofDate){
  54. result.add(sdf.format((Date)value));
  55. }else{
  56. result.add(value.toString());
  57. }
  58. }
  59. }
  60. row.setResult(result);
  61. rows.add(row);
  62. }
  63. worksheet.setRows(rows);
  64. body.setAttribute("worksheet",worksheet);
  65. writer.print(body.toString());
  66. writer.flush();
  67. rows.clear();
  68. rows=null;
  69. worksheet=null;
  70. body=null;
  71. Runtime.getRuntime().gc();
  72. System.out.println("正在生成excel文件的sheet"+(i+1));
  73. }
  74. //写入excel文件尾部
  75. writer.print("</Workbook>");
  76. writer.flush();
  77. writer.close();
  78. System.out.println("生成excel文件完成");
  79. longendTime=System.currentTimeMillis();
  80. System.out.println("用时="+((endTime-startTimne)/1000)+"秒");
 long startTimne = System.currentTimeMillis();
        StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate");
        //写入excel文件头部信息
        StringTemplate head =  stGroup.getInstanceOf("head");
        File file = new File("D:/output2.xls");
        PrintWriter writer = new PrintWriter(new BufferedOutputStream(new FileOutputStream(file)));
        writer.print(head.toString());
        writer.flush();
        int totalRowNum = listWinningRecordDTOList.size();
        int maxRowNum = 60000;
        int sheets = totalRowNum % 60000 == 0 ? (totalRowNum/maxRowNum) : (totalRowNum/maxRowNum +1);
        //excel单表最大行数是65535
        List record = listWinningRecordDTOList;
        List<String> title = new ArrayList<String>();
        List<Method> getMethods = new ArrayList<Method>();
        Class<?> clazz = record.get(0).getClass();
        Field[] fields = clazz.getDeclaredFields();
        if(fields != null && fields.length > 0){
            for(Field field : fields){
                if(!"serialVersionUID".equals(field.getName())) {
                    title.add(field.getName());
                    getMethods.add(clazz.getDeclaredMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)));
                }
            }
        }
//        BeanInfo beanInfo=Introspector.getBeanInfo(clazz,Object.class);
//        PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
//        for(PropertyDescriptor propertyDescriptor : proDescrtptors){
//            title.add(propertyDescriptor.getName());
//            getMethods.add(propertyDescriptor.getReadMethod());
//        }
        int columnLength = title.size();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //写入excel文件数据信息
        for(int i=0;i<sheets;i++){
            StringTemplate body =  stGroup.getInstanceOf("body");
            Worksheet worksheet = new Worksheet();
            worksheet.setTitle(title);
            worksheet.setSheet(" "+(i+1)+" ");
            worksheet.setColumnNum(columnLength);
            worksheet.setRowNum(maxRowNum+1);
            List<Row> rows = new ArrayList<Row>();
            int startIndex = i*maxRowNum;
            int endIndex = Math.min((i+1)*maxRowNum -1,totalRowNum-1);
            for(int j=startIndex;j<=endIndex;j++){
                Row row = new Row();
                List<String> result = new ArrayList<String>(columnLength);
                for(int n=0;n<columnLength;n++){
                    Object value = getMethods.get(n).invoke(record.get(j));
                    if(value == null){
                        result.add("");
                    }else{
                        if(value instanceof Date){
                            result.add(sdf.format((Date)value));
                        }else{
                            result.add(value.toString());
                        }
                    }
                }
                row.setResult(result);
                rows.add(row);
            }
            worksheet.setRows(rows);
            body.setAttribute("worksheet", worksheet);
            writer.print(body.toString());
            writer.flush();
            rows.clear();
            rows = null;
            worksheet = null;
            body = null;
            Runtime.getRuntime().gc();
            System.out.println("正在生成excel文件的 sheet"+(i+1));
        }
        //写入excel文件尾部
        writer.print("</Workbook>");
        writer.flush();
        writer.close();
        System.out.println("生成excel文件完成");
        long endTime = System.currentTimeMillis();
        System.out.println("用时="+((endTime-startTimne)/1000)+"秒");

整理后的公用类:

  1. importorg.antlr.stringtemplate.StringTemplate;
  2. importorg.antlr.stringtemplate.StringTemplateGroup;
  3. importjava.io.*;
  4. importjava.lang.reflect.Field;
  5. importjava.lang.reflect.InvocationTargetException;
  6. importjava.lang.reflect.Method;
  7. importjava.text.SimpleDateFormat;
  8. importjava.util.ArrayList;
  9. importjava.util.Date;
  10. importjava.util.List;
  11. /**
  12. *CreatedbyAdministratoron2016/2/25.
  13. */
  14. publicclassExcelStUtil{
  15. publicstaticvoidexport(OutputStreamoutputStream,Listtarget)throwsNoSuchMethodException,InvocationTargetException,IllegalAccessException{
  16. longstartTime=System.currentTimeMillis();
  17. StringTemplateGroupstGroup=newStringTemplateGroup("stringTemplate");
  18. //解决可能发生的中文乱码
  19. stGroup.setFileCharEncoding("UTF-8");
  20. //写入excel文件头部信息
  21. StringTemplatehead=stGroup.getInstanceOf("st/head");
  22. PrintWriterwriter=newPrintWriter(newBufferedOutputStream(outputStream));
  23. writer.print(head.toString());
  24. writer.flush();
  25. inttotalRowNum=target.size();
  26. intmaxRowNum=60000;
  27. intsheets=totalRowNum%60000==0?(totalRowNum/maxRowNum):(totalRowNum/maxRowNum+1);
  28. //excel单表最大行数是65535
  29. Listrecord=target;
  30. List<String>title=newArrayList<String>();
  31. List<Method>getMethods=newArrayList<Method>();
  32. Class<?>clazz=record.get(0).getClass();
  33. Field[]fields=clazz.getDeclaredFields();
  34. if(fields!=null&&fields.length>0){
  35. for(Fieldfield:fields){
  36. if(!"serialVersionUID".equals(field.getName())){
  37. title.add(field.getName());
  38. getMethods.add(clazz.getDeclaredMethod("get"+field.getName().substring(0,1).toUpperCase()+field.getName().substring(1)));
  39. }
  40. }
  41. }
  42. //BeanInfobeanInfo=Introspector.getBeanInfo(clazz,Object.class);
  43. //PropertyDescriptor[]proDescrtptors=beanInfo.getPropertyDescriptors();
  44. //for(PropertyDescriptorpropertyDescriptor:proDescrtptors){
  45. //title.add(propertyDescriptor.getName());
  46. //getMethods.add(propertyDescriptor.getReadMethod());
  47. //}
  48. intcolumnLength=title.size();
  49. SimpleDateFormatsdf=newSimpleDateFormat("yyyy-MM-ddHH:mm:ss");
  50. //写入excel文件数据信息
  51. for(inti=0;i<sheets;i++){
  52. StringTemplatebody=stGroup.getInstanceOf("st/body");
  53. Worksheetworksheet=newWorksheet();
  54. worksheet.setTitle(title);
  55. worksheet.setSheet(""+(i+1)+"");
  56. worksheet.setColumnNum(columnLength);
  57. worksheet.setRowNum(maxRowNum+1);
  58. List<Row>rows=newArrayList<Row>();
  59. intstartIndex=i*maxRowNum;
  60. intendIndex=Math.min((i+1)*maxRowNum-1,totalRowNum-1);
  61. for(intj=startIndex;j<=endIndex;j++){
  62. Rowrow=newRow();
  63. List<String>result=newArrayList<String>(columnLength);
  64. for(intn=0;n<columnLength;n++){
  65. Objectvalue=getMethods.get(n).invoke(record.get(j));
  66. if(value==null){
  67. result.add("");
  68. }else{
  69. if(valueinstanceofDate){
  70. result.add(sdf.format((Date)value));
  71. }else{
  72. result.add(value.toString());
  73. }
  74. }
  75. }
  76. row.setResult(result);
  77. rows.add(row);
  78. }
  79. worksheet.setRows(rows);
  80. body.setAttribute("worksheet",worksheet);
  81. writer.print(body.toString());
  82. writer.flush();
  83. rows.clear();
  84. rows=null;
  85. worksheet=null;
  86. body=null;
  87. Runtime.getRuntime().gc();
  88. System.out.println("正在生成excel文件的sheet"+(i+1));
  89. }
  90. //写入excel文件尾部
  91. writer.print("</Workbook>");
  92. writer.flush();
  93. writer.close();
  94. System.out.println("生成excel文件完成");
  95. longendTime=System.currentTimeMillis();
  96. System.out.println("用时="+((endTime-startTime)/1000)+"秒");
  97. }
  98. publicstaticvoidmain(String[]args)throwsIOException,NoSuchMethodException,IllegalAccessException,InvocationTargetException{
  99. System.out.println(Thread.currentThread().getContextClassLoader().getResource("").getPath());
  100. System.out.println(ExcelStUtil.class.getResource("").getPath());
  101. System.out.println(ExcelStUtil.class.getClassLoader().getResource("").getPath());
  102. List<Sample>result=newArrayList<Sample>();
  103. for(inti=0;i<100;i++){
  104. result.add(newSample("放大双方的"+String.valueOf(i),String.valueOf(i)));
  105. }
  106. //OutputStreamoutputStream=newFileOutputStream("D:/output2.xls");
  107. ByteArrayOutputStreambyteArrayOutputStream=newByteArrayOutputStream();
  108. ExcelStUtil.export(byteArrayOutputStream,result);
  109. //ByteArrayInputStreambyteArrayInputStream=newByteArrayInputStream(byteArrayOutputStream.toByteArray());
  110. //解决可能发生的中文乱码
  111. ByteArrayInputStreambyteArrayInputStream=newByteArrayInputStream(byteArrayOutputStream.toString().getBytes("UTF-8"));
  112. Filefile=newFile("D:/output2.xls");
  113. OutputStreamoutput=newFileOutputStream(file);
  114. BufferedOutputStreambufferedOutput=newBufferedOutputStream(output);
  115. //bufferedOutput.write(byteArrayOutputStream.toByteArray());
  116. bufferedOutput.write(byteArrayOutputStream.toString().getBytes("UTF-8"));
  117. bufferedOutput.flush();
  118. bufferedOutput.close();
  119. }
  120. }
import org.antlr.stringtemplate.StringTemplate;
import org.antlr.stringtemplate.StringTemplateGroup;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * Created by Administrator on 2016/2/25.
 */
public class ExcelStUtil {
    public static void export(OutputStream outputStream,List target) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        long startTime = System.currentTimeMillis();
        StringTemplateGroup stGroup = new StringTemplateGroup("stringTemplate");
        //解决可能发生的中文乱码
        stGroup.setFileCharEncoding("UTF-8");
        //写入excel文件头部信息
        StringTemplate head =  stGroup.getInstanceOf("st/head");
        PrintWriter writer = new PrintWriter(new BufferedOutputStream(outputStream));
        writer.print(head.toString());
        writer.flush();
        int totalRowNum = target.size();
        int maxRowNum = 60000;
        int sheets = totalRowNum % 60000 == 0 ? (totalRowNum/maxRowNum) : (totalRowNum/maxRowNum +1);
        //excel单表最大行数是65535
        List record = target;
        List<String> title = new ArrayList<String>();
        List<Method> getMethods = new ArrayList<Method>();
        Class<?> clazz = record.get(0).getClass();
        Field[] fields = clazz.getDeclaredFields();
        if(fields != null && fields.length > 0){
            for(Field field : fields){
                if(!"serialVersionUID".equals(field.getName())) {
                    title.add(field.getName());
                    getMethods.add(clazz.getDeclaredMethod("get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1)));
                }
            }
        }
//        BeanInfo beanInfo=Introspector.getBeanInfo(clazz,Object.class);
//        PropertyDescriptor[] proDescrtptors=beanInfo.getPropertyDescriptors();
//        for(PropertyDescriptor propertyDescriptor : proDescrtptors){
//            title.add(propertyDescriptor.getName());
//            getMethods.add(propertyDescriptor.getReadMethod());
//        }
        int columnLength = title.size();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //写入excel文件数据信息
        for(int i=0;i<sheets;i++){
            StringTemplate body =  stGroup.getInstanceOf("st/body");
            Worksheet worksheet = new Worksheet();
            worksheet.setTitle(title);
            worksheet.setSheet(" "+(i+1)+" ");
            worksheet.setColumnNum(columnLength);
            worksheet.setRowNum(maxRowNum+1);
            List<Row> rows = new ArrayList<Row>();
            int startIndex = i*maxRowNum;
            int endIndex = Math.min((i+1)*maxRowNum -1,totalRowNum-1);
            for(int j=startIndex;j<=endIndex;j++){
                Row row = new Row();
                List<String> result = new ArrayList<String>(columnLength);
                for(int n=0;n<columnLength;n++){
                    Object value = getMethods.get(n).invoke(record.get(j));
                    if(value == null){
                        result.add("");
                    }else{
                        if(value instanceof Date){
                            result.add(sdf.format((Date)value));
                        }else{
                            result.add(value.toString());
                        }
                    }
                }
                row.setResult(result);
                rows.add(row);
            }
            worksheet.setRows(rows);
            body.setAttribute("worksheet", worksheet);
            writer.print(body.toString());
            writer.flush();
            rows.clear();
            rows = null;
            worksheet = null;
            body = null;
            Runtime.getRuntime().gc();
            System.out.println("正在生成excel文件的 sheet"+(i+1));
        }
        //写入excel文件尾部
        writer.print("</Workbook>");
        writer.flush();
        writer.close();
        System.out.println("生成excel文件完成");
        long endTime = System.currentTimeMillis();
        System.out.println("用时="+((endTime-startTime)/1000)+"秒");
    }
    public static void main(String[] args) throws IOException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        System.out.println(Thread.currentThread().getContextClassLoader().getResource("").getPath());
        System.out.println(ExcelStUtil.class.getResource("").getPath());
        System.out.println(ExcelStUtil.class.getClassLoader().getResource("").getPath());
        List<Sample> result = new ArrayList<Sample>();
        for(int i=0;i<100;i++){
            result.add(new Sample("放大双方的"+String.valueOf(i),String.valueOf(i)));
        }
        //OutputStream outputStream = new FileOutputStream("D:/output2.xls");
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ExcelStUtil.export(byteArrayOutputStream,result);
        //ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        //解决可能发生的中文乱码
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toString().getBytes("UTF-8"));
        File file = new File("D:/output2.xls");
        OutputStream output = new FileOutputStream(file);
        BufferedOutputStream bufferedOutput = new BufferedOutputStream(output);
        //bufferedOutput.write(byteArrayOutputStream.toByteArray());
        bufferedOutput.write(byteArrayOutputStream.toString().getBytes("UTF-8"));
        bufferedOutput.flush();
        bufferedOutput.close();
    }
}

免责声明:文章转载自《Java 使用stringTemplate导出大批量数据excel(百万级)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇oracle缩小表空间双网卡绑定-bond0下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Excel导入导出工具(简单、好用且轻量级的海量Excel文件导入导出解决方案.)

Excel导入导出工具(简单、好用且轻量级的海量Excel文件导入导出解决方案.) 置顶 2019-09-07 16:47:10 $9420阅读数 261更多分类专栏: java   版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net...

ASP.NET MVC:通过 FileResult 向 浏览器 发送文件

FileResult is an abstract base class for all the others. FileContentResult - you use it when you have a byte array you would like to return as a file FilePathResult - when you...

Java 音频加水印

先解释一下什么是音频加水印: 音频加水印就是在一段音频中通过混音加入另一段音频,目的是让音频可以公开分享并有效保护原创。 本文主要纪录自己关于给音频加水印的技术调研。 开发语言:Java,开发所处系统环境Mac 使用了开源软件:FFmpeg 4.2.4 FFmpeg官网下载链接:https://ffmpeg.org/download.html#build-...

将list分成等数量

import java.util.ArrayList; import java.util.List; public class CollectionGroupUtil { public static List groupListByQuantity(List list, int quantity) { if (list...

JSON数据的处理中的特殊字符

     JSON如今是非经常见的处理数据的方式了。但因为自己使用的是反射获取数据,必须自己处理特殊字符,但总是发现有一些看不见的字符在前台 var obj = jQuery.parseJSON(msg);会转换失败。     比如例如以下在Vs中能够看到仅仅有两个字符    可实际上却有三个字符,使用notepad++打开 一直不明确这些字符是怎样进...

Hive metastore源码阅读(一)

不要问我为什么,因为爱,哈哈哈哈。。。进入正题,最近做项目顺带学习了下hive metastore的源码,进行下知识总结。 hive metastore的整体架构如图: 一、组成结构: 如图我们可以看到,hive metastore的组成结构分为 客户端 服务端 ,那么下来我们逐一进行分析: 1、客户端 从代码的角度来看:尼玛太多了。。我们从入口HIV...