欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

POI读写大数据Excel

程序员文章站 2022-03-24 09:16:01
...

转[http://blog.csdn.net/goodkuang2012/article/details/7350985#]]

 

目前处理Excel的开源javaAPI主要有两种,一是Jxl(Java Excel API),Jxl只支持Excel2003以下的版本。另外一种是Apache的Jakarta POI,相比于Jxl,POI对微软办公文档的支持更加强大,但是它使用复杂,上手慢。POI可支持更高的Excel版本2007。对Excel的读取,POI有两种模式,一是用户模式,这种方式同Jxl的使用很类似,使用简单,都是将文件一次性读到内存,文件小的时候,没有什么问题,当文件大的时候,就会出现OutOfMemory的内存溢出问题。第二种是事件驱动模式,拿Excel2007来说,其内容采用XML的格式来存储,所以处理excel就是解析XML,而目前使用事件驱动模式解析XML的API是SAX(Simple API for XML),这种模型在读取XML文档时,并没有将整个文档读入内存,而是按顺序将整个文档解析完,在解析过程中,会主动产生事件交给程序中相应的处理函数来处理当前内容。因此这种方式对系统资源要求不高,可以处理海量数据。笔者曾经做过测试,这种方法处理一千万条,每条五列的数据花费大约11分钟。可见处理海量数据的文件事件驱动是一个很好的方式。而本文中用到的AbstractExcel2003Reader、AbstractExcel2007Reader对Excel的读取都是采用这种POI的事件驱动模式。至于Excel的写操作,对较高版本的Excel2007,POI提供了很好的支持,主要流程是第一步构建工作薄和电子表格对象,第二步在一个流中构建文本文件,第三步使用流中产生的数据替换模板中的电子表格。这种方式也可以处理海量数据文件。AbstractExcel2007Writer就是使用这种方式进行写操作。对于写入较低版本的Excel2003,POI使用了用户模式来处理,就是将整个文档加载进内存,如果数据量大的话就会出现内存溢出的问题,Excel2003Writer就是使用这种方式。据笔者的测试,如果数据量大于3万条,每条8列的话,就会报OutOfMemory的错误。Excel2003中每个电子表格的记录数必须在65536以下,否则就会发生异常。目前还没有好的解决方案,建议对于海量数据写入操作,尽量使用Excel2007。

[java] view plaincopy
 
  1. /** 
  2.  * 抽象Excel2003读取器,通过实现HSSFListener监听器,采用事件驱动模式解析excel2003 
  3.  * 中的内容,遇到特定事件才会触发,大大减少了内存的使用。 
  4.  * 
  5.  */  
  6. public  class Excel2003Reader implements HSSFListener{  
  7.     private int minColumns = -1;  
  8.     private POIFSFileSystem fs;  
  9.     private int lastRowNumber;  
  10.     private int lastColumnNumber;  
  11.   
  12.     /** Should we output the formula, or the value it has? */  
  13.     private boolean outputFormulaValues = true;  
  14.   
  15.     /** For parsing Formulas */  
  16.     private SheetRecordCollectingListener workbookBuildingListener;  
  17.     //excel2003工作薄  
  18.     private HSSFWorkbook stubWorkbook;  
  19.   
  20.     // Records we pick up as we process  
  21.     private SSTRecord sstRecord;  
  22.     private FormatTrackingHSSFListener formatListener;  
  23.   
  24.     //表索引  
  25.     private int sheetIndex = -1;  
  26.     private BoundSheetRecord[] orderedBSRs;  
  27.     @SuppressWarnings("unchecked")  
  28.     private ArrayList boundSheetRecords = new ArrayList();  
  29.   
  30.     // For handling formulas with string results  
  31.     private int nextRow;  
  32.     private int nextColumn;  
  33.     private boolean outputNextStringRecord;  
  34.     //当前行  
  35.     private int curRow = 0;  
  36.     //存储行记录的容器  
  37.     private List<String> rowlist = new ArrayList<String>();;  
  38.     @SuppressWarnings"unused")  
  39.     private String sheetName;  
  40.       
  41.     private IRowReader rowReader;  
  42.   
  43.       
  44.     public void setRowReader(IRowReader rowReader){  
  45.         this.rowReader = rowReader;  
  46.     }  
  47.       
  48.     /** 
  49.      * 遍历excel下所有的sheet 
  50.      * @throws IOException 
  51.      */  
  52.     public void process(String fileName) throws IOException {  
  53.         this.fs = new POIFSFileSystem(new FileInputStream(fileName));  
  54.         MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(  
  55.                 this);  
  56.         formatListener = new FormatTrackingHSSFListener(listener);  
  57.         HSSFEventFactory factory = new HSSFEventFactory();  
  58.         HSSFRequest request = new HSSFRequest();  
  59.         if (outputFormulaValues) {  
  60.             request.addListenerForAllRecords(formatListener);  
  61.         } else {  
  62.             workbookBuildingListener = new SheetRecordCollectingListener(  
  63.                     formatListener);  
  64.             request.addListenerForAllRecords(workbookBuildingListener);  
  65.         }  
  66.         factory.processWorkbookEvents(request, fs);  
  67.     }  
  68.       
  69.     /** 
  70.      * HSSFListener 监听方法,处理 Record 
  71.      */  
  72.     @SuppressWarnings("unchecked")  
  73.     public void processRecord(Record record) {  
  74.         int thisRow = -1;  
  75.         int thisColumn = -1;  
  76.         String thisStr = null;  
  77.         String value = null;  
  78.         switch (record.getSid()) {  
  79.             case BoundSheetRecord.sid:  
  80.                 boundSheetRecords.add(record);  
  81.                 break;  
  82.             case BOFRecord.sid:  
  83.                 BOFRecord br = (BOFRecord) record;  
  84.                 if (br.getType() == BOFRecord.TYPE_WORKSHEET) {  
  85.                     // 如果有需要,则建立子工作薄  
  86.                     if (workbookBuildingListener != null && stubWorkbook == null) {  
  87.                         stubWorkbook = workbookBuildingListener  
  88.                                 .getStubHSSFWorkbook();  
  89.                     }  
  90.                       
  91.                     sheetIndex++;  
  92.                     if (orderedBSRs == null) {  
  93.                         orderedBSRs = BoundSheetRecord  
  94.                                 .orderByBofPosition(boundSheetRecords);  
  95.                     }  
  96.                     sheetName = orderedBSRs[sheetIndex].getSheetname();  
  97.                 }  
  98.                 break;  
  99.       
  100.             case SSTRecord.sid:  
  101.                 sstRecord = (SSTRecord) record;  
  102.                 break;  
  103.       
  104.             case BlankRecord.sid:  
  105.                 BlankRecord brec = (BlankRecord) record;  
  106.                 thisRow = brec.getRow();  
  107.                 thisColumn = brec.getColumn();  
  108.                 thisStr = "";  
  109.                 rowlist.add(thisColumn, thisStr);  
  110.                 break;  
  111.             case BoolErrRecord.sid: //单元格为布尔类型  
  112.                 BoolErrRecord berec = (BoolErrRecord) record;  
  113.                 thisRow = berec.getRow();  
  114.                 thisColumn = berec.getColumn();  
  115.                 thisStr = berec.getBooleanValue()+"";  
  116.                 rowlist.add(thisColumn, thisStr);  
  117.                 break;  
  118.       
  119.             case FormulaRecord.sid: //单元格为公式类型  
  120.                 FormulaRecord frec = (FormulaRecord) record;  
  121.                 thisRow = frec.getRow();  
  122.                 thisColumn = frec.getColumn();  
  123.                 if (outputFormulaValues) {  
  124.                     if (Double.isNaN(frec.getValue())) {  
  125.                         // Formula result is a string  
  126.                         // This is stored in the next record  
  127.                         outputNextStringRecord = true;  
  128.                         nextRow = frec.getRow();  
  129.                         nextColumn = frec.getColumn();  
  130.                     } else {  
  131.                         thisStr = formatListener.formatNumberDateCell(frec);  
  132.                     }  
  133.                 } else {  
  134.                     thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook,  
  135.                             frec.getParsedExpression()) + '"';  
  136.                 }  
  137.                 rowlist.add(thisColumn,thisStr);  
  138.                 break;  
  139.             case StringRecord.sid://单元格中公式的字符串  
  140.                 if (outputNextStringRecord) {  
  141.                     // String for formula  
  142.                     StringRecord srec = (StringRecord) record;  
  143.                     thisStr = srec.getString();  
  144.                     thisRow = nextRow;  
  145.                     thisColumn = nextColumn;  
  146.                     outputNextStringRecord = false;  
  147.                 }  
  148.                 break;  
  149.             case LabelRecord.sid:  
  150.                 LabelRecord lrec = (LabelRecord) record;  
  151.                 curRow = thisRow = lrec.getRow();  
  152.                 thisColumn = lrec.getColumn();  
  153.                 value = lrec.getValue().trim();  
  154.                 value = value.equals("")?" ":value;  
  155.                 this.rowlist.add(thisColumn, value);  
  156.                 break;  
  157.             case LabelSSTRecord.sid:  //单元格为字符串类型  
  158.                 LabelSSTRecord lsrec = (LabelSSTRecord) record;  
  159.                 curRow = thisRow = lsrec.getRow();  
  160.                 thisColumn = lsrec.getColumn();  
  161.                 if (sstRecord == null) {  
  162.                     rowlist.add(thisColumn, " ");  
  163.                 } else {  
  164.                     value =  sstRecord  
  165.                     .getString(lsrec.getSSTIndex()).toString().trim();  
  166.                     value = value.equals("")?" ":value;  
  167.                     rowlist.add(thisColumn,value);  
  168.                 }  
  169.                 break;  
  170.             case NumberRecord.sid:  //单元格为数字类型  
  171.                 NumberRecord numrec = (NumberRecord) record;  
  172.                 curRow = thisRow = numrec.getRow();  
  173.                 thisColumn = numrec.getColumn();  
  174.                 value = formatListener.formatNumberDateCell(numrec).trim();  
  175.                 value = value.equals("")?" ":value;  
  176.                 // 向容器加入列值  
  177.                 rowlist.add(thisColumn, value);  
  178.                 break;  
  179.             default:  
  180.                 break;  
  181.         }  
  182.   
  183.         // 遇到新行的操作  
  184.         if (thisRow != -1 && thisRow != lastRowNumber) {  
  185.             lastColumnNumber = -1;  
  186.         }  
  187.   
  188.         // 空值的操作  
  189.         if (record instanceof MissingCellDummyRecord) {  
  190.             MissingCellDummyRecord mc = (MissingCellDummyRecord) record;  
  191.             curRow = thisRow = mc.getRow();  
  192.             thisColumn = mc.getColumn();  
  193.             rowlist.add(thisColumn," ");  
  194.         }  
  195.   
  196.         // 更新行和列的值  
  197.         if (thisRow > -1)  
  198.             lastRowNumber = thisRow;  
  199.         if (thisColumn > -1)  
  200.             lastColumnNumber = thisColumn;  
  201.   
  202.         // 行结束时的操作  
  203.         if (record instanceof LastCellOfRowDummyRecord) {  
  204.             if (minColumns > 0) {  
  205.                 // 列值重新置空  
  206.                 if (lastColumnNumber == -1) {  
  207.                     lastColumnNumber = 0;  
  208.                 }  
  209.             }  
  210.             lastColumnNumber = -1;  
  211.                 // 每行结束时, 调用getRows() 方法  
  212.             rowReader.getRows(sheetIndex,curRow, rowlist);  
  213.               
  214.             // 清空容器  
  215.             rowlist.clear();  
  216.         }  
  217.     }  
  218.       
  219. }  
[java] view plaincopy
 
  1. /** 
  2.  * 抽象Excel2007读取器,excel2007的底层数据结构是xml文件,采用SAX的事件驱动的方法解析 
  3.  * xml,需要继承DefaultHandler,在遇到文件内容时,事件会触发,这种做法可以大大降低 
  4.  * 内存的耗费,特别使用于大数据量的文件。 
  5.  * 
  6.  */  
  7. public class Excel2007Reader extends DefaultHandler {  
  8.     //共享字符串表  
  9.     private SharedStringsTable sst;  
  10.     //上一次的内容  
  11.     private String lastContents;  
  12.     private boolean nextIsString;  
  13.   
  14.     private int sheetIndex = -1;  
  15.     private List<String> rowlist = new ArrayList<String>();  
  16.     //当前行  
  17.     private int curRow = 0;  
  18.     //当前列  
  19.     private int curCol = 0;  
  20.     //日期标志  
  21.     private boolean dateFlag;  
  22.     //数字标志  
  23.     private boolean numberFlag;  
  24.       
  25.     private boolean isTElement;  
  26.       
  27.     private IRowReader rowReader;  
  28.       
  29.     public void setRowReader(IRowReader rowReader){  
  30.         this.rowReader = rowReader;  
  31.     }  
  32.       
  33.     /**只遍历一个电子表格,其中sheetId为要遍历的sheet索引,从1开始,1-3 
  34.      * @param filename 
  35.      * @param sheetId 
  36.      * @throws Exception 
  37.      */  
  38.     public void processOneSheet(String filename,int sheetId) throws Exception {  
  39.         OPCPackage pkg = OPCPackage.open(filename);  
  40.         XSSFReader r = new XSSFReader(pkg);  
  41.         SharedStringsTable sst = r.getSharedStringsTable();  
  42.         XMLReader parser = fetchSheetParser(sst);  
  43.           
  44.         // 根据 rId# 或 rSheet# 查找sheet  
  45.         InputStream sheet2 = r.getSheet("rId"+sheetId);  
  46.         sheetIndex++;  
  47.         InputSource sheetSource = new InputSource(sheet2);  
  48.         parser.parse(sheetSource);  
  49.         sheet2.close();  
  50.     }  
  51.   
  52.     /** 
  53.      * 遍历工作簿中所有的电子表格 
  54.      * @param filename 
  55.      * @throws Exception 
  56.      */  
  57.     public void process(String filename) throws Exception {  
  58.         OPCPackage pkg = OPCPackage.open(filename);  
  59.         XSSFReader r = new XSSFReader(pkg);  
  60.         SharedStringsTable sst = r.getSharedStringsTable();  
  61.         XMLReader parser = fetchSheetParser(sst);  
  62.         Iterator<InputStream> sheets = r.getSheetsData();  
  63.         while (sheets.hasNext()) {  
  64.             curRow = 0;  
  65.             sheetIndex++;  
  66.             InputStream sheet = sheets.next();  
  67.             InputSource sheetSource = new InputSource(sheet);  
  68.             parser.parse(sheetSource);  
  69.             sheet.close();  
  70.         }  
  71.     }  
  72.   
  73.     public XMLReader fetchSheetParser(SharedStringsTable sst)  
  74.             throws SAXException {  
  75.         XMLReader parser = XMLReaderFactory  
  76.                 .createXMLReader("org.apache.xerces.parsers.SAXParser");  
  77.         this.sst = sst;  
  78.         parser.setContentHandler(this);  
  79.         return parser;  
  80.     }  
  81.   
  82.     public void startElement(String uri, String localName, String name,  
  83.             Attributes attributes) throws SAXException {  
  84.           
  85.         // c => 单元格  
  86.         if ("c".equals(name)) {  
  87.             // 如果下一个元素是 SST 的索引,则将nextIsString标记为true  
  88.             String cellType = attributes.getValue("t");  
  89.             if ("s".equals(cellType)) {  
  90.                 nextIsString = true;  
  91.             } else {  
  92.                 nextIsString = false;  
  93.             }  
  94.             //日期格式  
  95.             String cellDateType = attributes.getValue("s");  
  96.             if ("1".equals(cellDateType)){  
  97.                 dateFlag = true;  
  98.             } else {  
  99.                 dateFlag = false;  
  100.             }  
  101.             String cellNumberType = attributes.getValue("s");  
  102.             if("2".equals(cellNumberType)){  
  103.                 numberFlag = true;  
  104.             } else {  
  105.                 numberFlag = false;  
  106.             }  
  107.               
  108.         }  
  109.         //当元素为t时  
  110.         if("t".equals(name)){  
  111.             isTElement = true;  
  112.         } else {  
  113.             isTElement = false;  
  114.         }  
  115.           
  116.         // 置空  
  117.         lastContents = "";  
  118.     }  
  119.   
  120.     public void endElement(String uri, String localName, String name)  
  121.             throws SAXException {  
  122.           
  123.         // 根据SST的索引值的到单元格的真正要存储的字符串  
  124.         // 这时characters()方法可能会被调用多次  
  125.         if (nextIsString) {  
  126.             try {  
  127.                 int idx = Integer.parseInt(lastContents);  
  128.                 lastContents = new XSSFRichTextString(sst.getEntryAt(idx))  
  129.                         .toString();  
  130.             } catch (Exception e) {  
  131.   
  132.             }  
  133.         }   
  134.         //t元素也包含字符串  
  135.         if(isTElement){  
  136.             String value = lastContents.trim();  
  137.             rowlist.add(curCol, value);  
  138.             curCol++;  
  139.             isTElement = false;  
  140.             // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引  
  141.             // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符  
  142.         } else if ("v".equals(name)) {  
  143.             String value = lastContents.trim();  
  144.             value = value.equals("")?" ":value;  
  145.             //日期格式处理  
  146.             if(dateFlag){  
  147.                  Date date = HSSFDateUtil.getJavaDate(Double.valueOf(value));  
  148.                  SimpleDateFormat dateFormat = new SimpleDateFormat(  
  149.                  "dd/MM/yyyy");  
  150.                  value = dateFormat.format(date);  
  151.             }   
  152.             //数字类型处理  
  153.             if(numberFlag){  
  154.                 BigDecimal bd = new BigDecimal(value);  
  155.                 value = bd.setScale(3,BigDecimal.ROUND_UP).toString();  
  156.             }  
  157.             rowlist.add(curCol, value);  
  158.             curCol++;  
  159.         }else {  
  160.             //如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法  
  161.             if (name.equals("row")) {  
  162.                 rowReader.getRows(sheetIndex,curRow,rowlist);  
  163.                 rowlist.clear();  
  164.                 curRow++;  
  165.                 curCol = 0;  
  166.             }  
  167.         }  
  168.           
  169.     }  
  170.   
  171.     public void characters(char[] ch, int start, int length)  
  172.             throws SAXException {  
  173.         //得到单元格内容的值  
  174.         lastContents += new String(ch, start, length);  
  175.     }  
  176. }  



[java] view plaincopy
 
  1. public class ExcelReaderUtil {  
  2.       
  3.     //excel2003扩展名  
  4.     public static final String EXCEL03_EXTENSION = ".xls";  
  5.     //excel2007扩展名  
  6.     public static final String EXCEL07_EXTENSION = ".xlsx";  
  7.       
  8.     /** 
  9.      * 读取Excel文件,可能是03也可能是07版本 
  10.      * @param excel03 
  11.      * @param excel07 
  12.      * @param fileName 
  13.      * @throws Exception  
  14.      */  
  15.     public static void readExcel(IRowReader reader,String fileName) throws Exception{  
  16.         // 处理excel2003文件  
  17.         if (fileName.endsWith(EXCEL03_EXTENSION)){  
  18.             Excel2003Reader excel03 = new Excel2003Reader();  
  19.             excel03.setRowReader(reader);  
  20.             excel03.process(fileName);  
  21.         // 处理excel2007文件  
  22.         } else if (fileName.endsWith(EXCEL07_EXTENSION)){  
  23.             Excel2007Reader excel07 = new Excel2007Reader();  
  24.             excel07.setRowReader(reader);  
  25.             excel07.process(fileName);  
  26.         } else {  
  27.             throw new  Exception("文件格式错误,fileName的扩展名只能是xls或xlsx。");  
  28.         }  
  29.     }  
  30. }  



[java] view plaincopy
 
  1. public interface IRowReader {  
  2.       
  3.     /**业务逻辑实现方法 
  4.      * @param sheetIndex 
  5.      * @param curRow 
  6.      * @param rowlist 
  7.      */  
  8.     public  void getRows(int sheetIndex,int curRow, List<String> rowlist);  
  9. }  



[java] view plaincopy
 
  1. public class RowReader implements IRowReader{  
  2.   
  3.   
  4.     /* 业务逻辑实现方法 
  5.      * @see com.eprosun.util.excel.IRowReader#getRows(int, int, java.util.List) 
  6.      */  
  7.     public void getRows(int sheetIndex, int curRow, List<String> rowlist) {  
  8.         // TODO Auto-generated method stub  
  9.         System.out.print(curRow+" ");  
  10.         for (int i = 0; i < rowlist.size(); i++) {  
  11.             System.out.print(rowlist.get(i) + " ");  
  12.         }  
  13.         System.out.println();  
  14.     }  
  15.   
  16. }  

 

[java] view plaincopy
 
  1. public class Main {  
  2.       
  3.     public static void main(String[] args) throws Exception {  
  4.         IRowReader reader = new RowReader();  
  5.         //ExcelReaderUtil.readExcel(reader, "F://te03.xls");  
  6.         ExcelReaderUtil.readExcel(reader, "F://test07.xlsx");  
  7.     }  
  8. }  



[java] view plaincopy
 
  1. public class Excel2003Writer {  
  2.   
  3.     /** 
  4.      * @param args 
  5.      */  
  6.     public static void main(String[] args) {  
  7.         try{      
  8.             System.out.println("开始写入excel2003....");  
  9.             writeExcel("tes2003.xls");  
  10.             System.out.println("写完xcel2003");  
  11.         } catch (IOException e) {  
  12.           
  13.         }  
  14.     }  
  15.       
  16.       
  17.     /** 
  18.      * 写入excel并填充内容,一个sheet只能写65536行以下,超出会报异常,写入时建议使用AbstractExcel2007Writer 
  19.      * @param fileName 
  20.      * @throws IOException 
  21.      */  
  22.     public static void writeExcel(String fileName) throws IOException{  
  23.               
  24.             // 创建excel2003对象  
  25.             Workbook wb = new HSSFWorkbook();  
  26.               
  27.             // 设置文件放置路径和文件名  
  28.             FileOutputStream fileOut = new FileOutputStream(fileName);  
  29.             // 创建新的表单  
  30.             Sheet sheet = wb.createSheet("newsheet");  
  31.             // 创建新行  
  32.             for(int i=0;i<20000;i++){  
  33.                 Row row = sheet.createRow(i);  
  34.                 // 创建单元格  
  35.                 Cell cell = row.createCell(0);  
  36.                 // 设置单元格值  
  37.                 cell.setCellValue(1);  
  38.                 row.createCell(1).setCellValue(1+i);  
  39.                 row.createCell(2).setCellValue(true);  
  40.                 row.createCell(3).setCellValue(0.43d);  
  41.                 row.createCell(4).setCellValue('d');  
  42.                 row.createCell(5).setCellValue("");  
  43.                 row.createCell(6).setCellValue("第七列"+i);  
  44.                 row.createCell(7).setCellValue("第八列"+i);  
  45.             }  
  46.             wb.write(fileOut);  
  47.             fileOut.close();  
  48.     }  
  49.   
  50.   
  51. }  




[java] view plaincopy
 
  1. /** 
  2.  * 抽象excel2007读入器,先构建.xlsx一张模板,改写模板中的sheet.xml,使用这种方法 
  3.  * 写入.xlsx文件,不需要太大的内存 
  4.  * 
  5.  */  
  6. public abstract class AbstractExcel2007Writer {  
  7.       
  8.     private SpreadsheetWriter sw;  
  9.   
  10.     /** 
  11.      * 写入电子表格的主要流程 
  12.      * @param fileName 
  13.      * @throws Exception 
  14.      */  
  15.     public void process(String fileName) throws Exception{  
  16.         // 建立工作簿和电子表格对象  
  17.         XSSFWorkbook wb = new XSSFWorkbook();  
  18.         XSSFSheet sheet = wb.createSheet("sheet1");  
  19.         // 持有电子表格数据的xml文件名 例如 /xl/worksheets/sheet1.xml  
  20.         String sheetRef = sheet.getPackagePart().getPartName().getName();  
  21.   
  22.         // 保存模板  
  23.         FileOutputStream os = new FileOutputStream("template.xlsx");  
  24.         wb.write(os);  
  25.         os.close();  
  26.           
  27.         // 生成xml文件  
  28.         File tmp = File.createTempFile("sheet"".xml");  
  29.         Writer fw = new FileWriter(tmp);  
  30.         sw = new SpreadsheetWriter(fw);  
  31.         generate();  
  32.         fw.close();  
  33.           
  34.         // 使用产生的数据替换模板  
  35.         File templateFile = new File("template.xlsx");  
  36.         FileOutputStream out = new FileOutputStream(fileName);  
  37.         substitute(templateFile, tmp, sheetRef.substring(1), out);  
  38.         out.close();  
  39.         //删除文件之前调用一下垃圾回收器,否则无法删除模板文件  
  40.         System.gc();  
  41.         // 删除临时模板文件  
  42.         if (templateFile.isFile()&&templateFile.exists()){  
  43.             templateFile.delete();  
  44.         }  
  45.     }  
  46.   
  47.     /** 
  48.      * 类使用者应该使用此方法进行写操作 
  49.      * @throws Exception 
  50.      */  
  51.     public abstract void generate() throws Exception;  
  52.   
  53.     public void beginSheet() throws IOException {  
  54.         sw.beginSheet();  
  55.     }  
  56.   
  57.     public void insertRow(int rowNum) throws IOException {  
  58.         sw.insertRow(rowNum);  
  59.     }  
  60.   
  61.     public void createCell(int columnIndex, String value) throws IOException {  
  62.         sw.createCell(columnIndex, value, -1);  
  63.     }  
  64.   
  65.     public void createCell(int columnIndex, double value) throws IOException {  
  66.         sw.createCell(columnIndex, value, -1);  
  67.     }  
  68.   
  69.     public void endRow() throws IOException {  
  70.         sw.endRow();  
  71.     }  
  72.   
  73.     public void endSheet() throws IOException {  
  74.         sw.endSheet();  
  75.     }  
  76.   
  77.     /** 
  78.      * 
  79.      * @param zipfile the template file 
  80.      * @param tmpfile the XML file with the sheet data 
  81.      * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml 
  82.      * @param out the stream to write the result to 
  83.      */  
  84.     private static void substitute(File zipfile, File tmpfile, String entry,  
  85.             OutputStream out) throws IOException {  
  86.         ZipFile zip = new ZipFile(zipfile);  
  87.         ZipOutputStream zos = new ZipOutputStream(out);  
  88.   
  89.         @SuppressWarnings("unchecked")  
  90.         Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();  
  91.         while (en.hasMoreElements()) {  
  92.             ZipEntry ze = en.nextElement();  
  93.             if (!ze.getName().equals(entry)) {  
  94.                 zos.putNextEntry(new ZipEntry(ze.getName()));  
  95.                 InputStream is = zip.getInputStream(ze);  
  96.                 copyStream(is, zos);  
  97.                 is.close();  
  98.             }  
  99.         }  
  100.         zos.putNextEntry(new ZipEntry(entry));  
  101.         InputStream is = new FileInputStream(tmpfile);  
  102.         copyStream(is, zos);  
  103.         is.close();  
  104.         zos.close();  
  105.     }  
  106.   
  107.     private static void copyStream(InputStream in, OutputStream out)  
  108.             throws IOException {  
  109.         byte[] chunk = new byte[1024];  
  110.         int count;  
  111.         while ((count = in.read(chunk)) >= 0) {  
  112.             out.write(chunk, 0, count);  
  113.         }  
  114.     }  
  115.   
  116.     /** 
  117.      * 在写入器中写入电子表格 
  118.      *  
  119.      */  
  120.     public static class SpreadsheetWriter {  
  121.         private final Writer _out;  
  122.         private int _rownum;  
  123.         private static String LINE_SEPARATOR = System.getProperty("line.separator");  
  124.   
  125.         public SpreadsheetWriter(Writer out) {  
  126.             _out = out;  
  127.         }  
  128.   
  129.         public void beginSheet() throws IOException {  
  130.             _out.write("<?xml version=\"1.0\" encoding=\"GB2312\"?>"  
  131.                             + "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");  
  132.             _out.write("<sheetData>"+LINE_SEPARATOR);  
  133.         }  
  134.   
  135.         public void endSheet() throws IOException {  
  136.             _out.write("</sheetData>");  
  137.             _out.write("</worksheet>");  
  138.         }  
  139.   
  140.         /** 
  141.          * 插入新行 
  142.          * 
  143.          * @param rownum 以0开始 
  144.          */  
  145.         public void insertRow(int rownum) throws IOException {  
  146.             _out.write("<row r=\"" + (rownum + 1) + "\">"+LINE_SEPARATOR);  
  147.             this._rownum = rownum;  
  148.         }  
  149.   
  150.         /** 
  151.          * 插入行结束标志 
  152.          */  
  153.         public void endRow() throws IOException {  
  154.             _out.write("</row>"+LINE_SEPARATOR);  
  155.         }  
  156.   
  157.         /** 
  158.          * 插入新列 
  159.          * @param columnIndex 
  160.          * @param value 
  161.          * @param styleIndex 
  162.          * @throws IOException 
  163.          */  
  164.         public void createCell(int columnIndex, String value, int styleIndex)  
  165.                 throws IOException {  
  166.             String ref = new CellReference(_rownum, columnIndex)  
  167.                     .formatAsString();  
  168.             _out.write("<c r=\"" + ref + "\" t=\"inlineStr\"");  
  169.             if (styleIndex != -1)  
  170.                 _out.write(" s=\"" + styleIndex + "\"");  
  171.             _out.write(">");  
  172.             _out.write("<is><t>"+XMLEncoder.encode(value)+"</t></is>");  
  173.             _out.write("</c>");  
  174.         }  
  175.   
  176.         public void createCell(int columnIndex, String value)  
  177.                 throws IOException {  
  178.             createCell(columnIndex, value, -1);  
  179.         }  
  180.   
  181.         public void createCell(int columnIndex, double value, int styleIndex)  
  182.                 throws IOException {  
  183.             String ref = new CellReference(_rownum, columnIndex)  
  184.                     .formatAsString();  
  185.             _out.write("<c r=\"" + ref + "\" t=\"n\"");  
  186.             if (styleIndex != -1)  
  187.                 _out.write(" s=\"" + styleIndex + "\"");  
  188.             _out.write(">");  
  189.             _out.write("<v>" + value + "</v>");  
  190.             _out.write("</c>");  
  191.         }  
  192.   
  193.         public void createCell(int columnIndex, double value)  
  194.                 throws IOException {  
  195.             createCell(columnIndex, value, -1);  
  196.         }  
  197.   
  198.         public void createCell(int columnIndex, Calendar value, int styleIndex)  
  199.                 throws IOException {  
  200.             createCell(columnIndex, DateUtil.getExcelDate(value, false),  
  201.                     styleIndex);  
  202.         }  
  203.     }  
  204. }  

 

[java] view plaincopy
 
  1. public class Excel2007WriterImpl extends AbstractExcel2007Writer{  
  2.   
  3.       
  4.     /** 
  5.      * @param args 
  6.      * @throws Exception 
  7.      */  
  8.     public static void main(String[] args) throws Exception {  
  9.         // TODO Auto-generated method stub  
  10.         System.out.println("............................");  
  11.         long start = System.currentTimeMillis();  
  12.         //构建excel2007写入器  
  13.         AbstractExcel2007Writer excel07Writer = new Excel2007WriterImpl();  
  14.         //调用处理方法  
  15.         excel07Writer.process("F://test07.xlsx");  
  16.         long end = System.currentTimeMillis();  
  17.         System.out.println("....................."+(end-start)/1000);  
  18.     }  
  19.   
  20.       
  21.     /*  
  22.      * 可根据需求重写此方法,对于单元格的小数或者日期格式,会出现精度问题或者日期格式转化问题,建议使用字符串插入方法 
  23.      * @see com.excel.ver2.AbstractExcel2007Writer#generate() 
  24.      */  
  25.     @Override  
  26.     public void generate()throws Exception {  
  27.         //电子表格开始  
  28.         beginSheet();  
  29.         for (int rownum = 0; rownum < 100; rownum++) {  
  30.             //插入新行  
  31.             insertRow(rownum);  
  32.             //建立新单元格,索引值从0开始,表示第一列  
  33.             createCell(0"中国<" + rownum + "!");  
  34.             createCell(134343.123456789);  
  35.             createCell(2"23.67%");  
  36.             createCell(3"12:12:23");  
  37.             createCell(4"2010-10-11 12:12:23");  
  38.             createCell(5"true");  
  39.             createCell(6"false");  
  40.             
  41.             //结束行  
  42.             endRow();  
  43.         }  
  44.         //电子表格结束  
  45.         endSheet();  
  46.     }  
  47.   
  48. }  



[java] view plaincopy
 
  1. public class XMLEncoder {  
  2.   
  3.     private static final String[] xmlCode = new String[256];  
  4.   
  5.     static {  
  6.         // Special characters  
  7.         xmlCode['\''] = "'";  
  8.         xmlCode['\"'] = """// double quote  
  9.         xmlCode['&'] = "&"// ampersand  
  10.         xmlCode['<'] = "<"// lower than  
  11.         xmlCode['>'] = ">"// greater than  
  12.     }  
  13.   
  14.     /** 
  15.      * <p> 
  16.      * Encode the given text into xml. 
  17.      * </p> 
  18.      *  
  19.      * @param string the text to encode 
  20.      * @return the encoded string 
  21.      */  
  22.     public static String encode(String string) {  
  23.         if (string == nullreturn "";  
  24.         int n = string.length();  
  25.         char character;  
  26.         String xmlchar;  
  27.         StringBuffer buffer = new StringBuffer();  
  28.         // loop over all the characters of the String.  
  29.         for (int i = 0; i < n; i++) {  
  30.             character = string.charAt(i);  
  31.             // the xmlcode of these characters are added to a StringBuffer one by one  
  32.             try {  
  33.                 xmlchar = xmlCode[character];  
  34.                 if (xmlchar == null) {  
  35.                     buffer.append(character);  
  36.                 } else {  
  37.                     buffer.append(xmlCode[character]);  
  38.                 }  
  39.             } catch (ArrayIndexOutOfBoundsException aioobe) {  
  40.                 buffer.append(character);  
  41.             }  
  42.         }  
  43.         return buffer.toString();  
  44.     }  
  45.   
  46. }