POI读写海量Excel

时间:2024-09-09 21:06:08

目前处理Excel的开源javaAPI主要有两种,一是Jxl(JavaExcel 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。

  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. /** Should we output the formula, or the value it has? */
  12. private boolean outputFormulaValues = true;
  13. /** For parsing Formulas */
  14. private SheetRecordCollectingListener workbookBuildingListener;
  15. //excel2003工作薄
  16. private HSSFWorkbook stubWorkbook;
  17. // Records we pick up as we process
  18. private SSTRecord sstRecord;
  19. private FormatTrackingHSSFListener formatListener;
  20. //表索引
  21. private int sheetIndex = -1;
  22. private BoundSheetRecord[] orderedBSRs;
  23. @SuppressWarnings("unchecked")
  24. private ArrayList boundSheetRecords = new ArrayList();
  25. // For handling formulas with string results
  26. private int nextRow;
  27. private int nextColumn;
  28. private boolean outputNextStringRecord;
  29. //当前行
  30. private int curRow = 0;
  31. //存储行记录的容器
  32. private List<String> rowlist = new ArrayList<String>();;
  33. @SuppressWarnings( "unused")
  34. private String sheetName;
  35. private IRowReader rowReader;
  36. public void setRowReader(IRowReader rowReader){
  37. this.rowReader = rowReader;
  38. }
  39. /**
  40. * 遍历excel下所有的sheet
  41. * @throws IOException
  42. */
  43. public void process(String fileName) throws IOException {
  44. this.fs = new POIFSFileSystem(new FileInputStream(fileName));
  45. MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(
  46. this);
  47. formatListener = new FormatTrackingHSSFListener(listener);
  48. HSSFEventFactory factory = new HSSFEventFactory();
  49. HSSFRequest request = new HSSFRequest();
  50. if (outputFormulaValues) {
  51. request.addListenerForAllRecords(formatListener);
  52. } else {
  53. workbookBuildingListener = new SheetRecordCollectingListener(
  54. formatListener);
  55. request.addListenerForAllRecords(workbookBuildingListener);
  56. }
  57. factory.processWorkbookEvents(request, fs);
  58. }
  59. /**
  60. * HSSFListener 监听方法,处理 Record
  61. */
  62. @SuppressWarnings("unchecked")
  63. public void processRecord(Record record) {
  64. int thisRow = -1;
  65. int thisColumn = -1;
  66. String thisStr = null;
  67. String value = null;
  68. switch (record.getSid()) {
  69. case BoundSheetRecord.sid:
  70. boundSheetRecords.add(record);
  71. break;
  72. case BOFRecord.sid:
  73. BOFRecord br = (BOFRecord) record;
  74. if (br.getType() == BOFRecord.TYPE_WORKSHEET) {
  75. // 如果有需要,则建立子工作薄
  76. if (workbookBuildingListener != null && stubWorkbook == null) {
  77. stubWorkbook = workbookBuildingListener
  78. .getStubHSSFWorkbook();
  79. }
  80. sheetIndex++;
  81. if (orderedBSRs == null) {
  82. orderedBSRs = BoundSheetRecord
  83. .orderByBofPosition(boundSheetRecords);
  84. }
  85. sheetName = orderedBSRs[sheetIndex].getSheetname();
  86. }
  87. break;
  88. case SSTRecord.sid:
  89. sstRecord = (SSTRecord) record;
  90. break;
  91. case BlankRecord.sid:
  92. BlankRecord brec = (BlankRecord) record;
  93. thisRow = brec.getRow();
  94. thisColumn = brec.getColumn();
  95. thisStr = "";
  96. rowlist.add(thisColumn, thisStr);
  97. break;
  98. case BoolErrRecord.sid: //单元格为布尔类型
  99. BoolErrRecord berec = (BoolErrRecord) record;
  100. thisRow = berec.getRow();
  101. thisColumn = berec.getColumn();
  102. thisStr = berec.getBooleanValue()+"";
  103. rowlist.add(thisColumn, thisStr);
  104. break;
  105. case FormulaRecord.sid: //单元格为公式类型
  106. FormulaRecord frec = (FormulaRecord) record;
  107. thisRow = frec.getRow();
  108. thisColumn = frec.getColumn();
  109. if (outputFormulaValues) {
  110. if (Double.isNaN(frec.getValue())) {
  111. // Formula result is a string
  112. // This is stored in the next record
  113. outputNextStringRecord = true;
  114. nextRow = frec.getRow();
  115. nextColumn = frec.getColumn();
  116. } else {
  117. thisStr = formatListener.formatNumberDateCell(frec);
  118. }
  119. } else {
  120. thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook,
  121. frec.getParsedExpression()) + '"';
  122. }
  123. rowlist.add(thisColumn,thisStr);
  124. break;
  125. case StringRecord.sid://单元格中公式的字符串
  126. if (outputNextStringRecord) {
  127. // String for formula
  128. StringRecord srec = (StringRecord) record;
  129. thisStr = srec.getString();
  130. thisRow = nextRow;
  131. thisColumn = nextColumn;
  132. outputNextStringRecord = false;
  133. }
  134. break;
  135. case LabelRecord.sid:
  136. LabelRecord lrec = (LabelRecord) record;
  137. curRow = thisRow = lrec.getRow();
  138. thisColumn = lrec.getColumn();
  139. value = lrec.getValue().trim();
  140. value = value.equals("")?" ":value;
  141. this.rowlist.add(thisColumn, value);
  142. break;
  143. case LabelSSTRecord.sid:  //单元格为字符串类型
  144. LabelSSTRecord lsrec = (LabelSSTRecord) record;
  145. curRow = thisRow = lsrec.getRow();
  146. thisColumn = lsrec.getColumn();
  147. if (sstRecord == null) {
  148. rowlist.add(thisColumn, " ");
  149. } else {
  150. value =  sstRecord
  151. .getString(lsrec.getSSTIndex()).toString().trim();
  152. value = value.equals("")?" ":value;
  153. rowlist.add(thisColumn,value);
  154. }
  155. break;
  156. case NumberRecord.sid:  //单元格为数字类型
  157. NumberRecord numrec = (NumberRecord) record;
  158. curRow = thisRow = numrec.getRow();
  159. thisColumn = numrec.getColumn();
  160. value = formatListener.formatNumberDateCell(numrec).trim();
  161. value = value.equals("")?" ":value;
  162. // 向容器加入列值
  163. rowlist.add(thisColumn, value);
  164. break;
  165. default:
  166. break;
  167. }
  168. // 遇到新行的操作
  169. if (thisRow != -1 && thisRow != lastRowNumber) {
  170. lastColumnNumber = -1;
  171. }
  172. // 空值的操作
  173. if (record instanceof MissingCellDummyRecord) {
  174. MissingCellDummyRecord mc = (MissingCellDummyRecord) record;
  175. curRow = thisRow = mc.getRow();
  176. thisColumn = mc.getColumn();
  177. rowlist.add(thisColumn," ");
  178. }
  179. // 更新行和列的值
  180. if (thisRow > -1)
  181. lastRowNumber = thisRow;
  182. if (thisColumn > -1)
  183. lastColumnNumber = thisColumn;
  184. // 行结束时的操作
  185. if (record instanceof LastCellOfRowDummyRecord) {
  186. if (minColumns > 0) {
  187. // 列值重新置空
  188. if (lastColumnNumber == -1) {
  189. lastColumnNumber = 0;
  190. }
  191. }
  192. lastColumnNumber = -1;
  193. // 每行结束时, 调用getRows() 方法
  194. rowReader.getRows(sheetIndex,curRow, rowlist);
  195. // 清空容器
  196. rowlist.clear();
  197. }
  198. }
  199. }
  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. private int sheetIndex = -1;
  14. private List<String> rowlist = new ArrayList<String>();
  15. //当前行
  16. private int curRow = 0;
  17. //当前列
  18. private int curCol = 0;
  19. //日期标志
  20. private boolean dateFlag;
  21. //数字标志
  22. private boolean numberFlag;
  23. private boolean isTElement;
  24. private IRowReader rowReader;
  25. public void setRowReader(IRowReader rowReader){
  26. this.rowReader = rowReader;
  27. }
  28. /**只遍历一个电子表格,其中sheetId为要遍历的sheet索引,从1开始,1-3
  29. * @param filename
  30. * @param sheetId
  31. * @throws Exception
  32. */
  33. public void processOneSheet(String filename,int sheetId) throws Exception {
  34. OPCPackage pkg = OPCPackage.open(filename);
  35. XSSFReader r = new XSSFReader(pkg);
  36. SharedStringsTable sst = r.getSharedStringsTable();
  37. XMLReader parser = fetchSheetParser(sst);
  38. // 根据 rId# 或 rSheet# 查找sheet
  39. InputStream sheet2 = r.getSheet("rId"+sheetId);
  40. sheetIndex++;
  41. InputSource sheetSource = new InputSource(sheet2);
  42. parser.parse(sheetSource);
  43. sheet2.close();
  44. }
  45. /**
  46. * 遍历工作簿中所有的电子表格
  47. * @param filename
  48. * @throws Exception
  49. */
  50. public void process(String filename) throws Exception {
  51. OPCPackage pkg = OPCPackage.open(filename);
  52. XSSFReader r = new XSSFReader(pkg);
  53. SharedStringsTable sst = r.getSharedStringsTable();
  54. XMLReader parser = fetchSheetParser(sst);
  55. Iterator<InputStream> sheets = r.getSheetsData();
  56. while (sheets.hasNext()) {
  57. curRow = 0;
  58. sheetIndex++;
  59. InputStream sheet = sheets.next();
  60. InputSource sheetSource = new InputSource(sheet);
  61. parser.parse(sheetSource);
  62. sheet.close();
  63. }
  64. }
  65. public XMLReader fetchSheetParser(SharedStringsTable sst)
  66. throws SAXException {
  67. XMLReader parser = XMLReaderFactory
  68. .createXMLReader("org.apache.xerces.parsers.SAXParser");
  69. this.sst = sst;
  70. parser.setContentHandler(this);
  71. return parser;
  72. }
  73. public void startElement(String uri, String localName, String name,
  74. Attributes attributes) throws SAXException {
  75. // c => 单元格
  76. if ("c".equals(name)) {
  77. // 如果下一个元素是 SST 的索引,则将nextIsString标记为true
  78. String cellType = attributes.getValue("t");
  79. if ("s".equals(cellType)) {
  80. nextIsString = true;
  81. } else {
  82. nextIsString = false;
  83. }
  84. //日期格式
  85. String cellDateType = attributes.getValue("s");
  86. if ("1".equals(cellDateType)){
  87. dateFlag = true;
  88. } else {
  89. dateFlag = false;
  90. }
  91. String cellNumberType = attributes.getValue("s");
  92. if("2".equals(cellNumberType)){
  93. numberFlag = true;
  94. } else {
  95. numberFlag = false;
  96. }
  97. }
  98. //当元素为t时
  99. if("t".equals(name)){
  100. isTElement = true;
  101. } else {
  102. isTElement = false;
  103. }
  104. // 置空
  105. lastContents = "";
  106. }
  107. public void endElement(String uri, String localName, String name)
  108. throws SAXException {
  109. // 根据SST的索引值的到单元格的真正要存储的字符串
  110. // 这时characters()方法可能会被调用多次
  111. if (nextIsString) {
  112. try {
  113. int idx = Integer.parseInt(lastContents);
  114. lastContents = new XSSFRichTextString(sst.getEntryAt(idx))
  115. .toString();
  116. } catch (Exception e) {
  117. }
  118. }
  119. //t元素也包含字符串
  120. if(isTElement){
  121. String value = lastContents.trim();
  122. rowlist.add(curCol, value);
  123. curCol++;
  124. isTElement = false;
  125. // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引
  126. // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
  127. } else if ("v".equals(name)) {
  128. String value = lastContents.trim();
  129. value = value.equals("")?" ":value;
  130. //日期格式处理
  131. if(dateFlag){
  132. Date date = HSSFDateUtil.getJavaDate(Double.valueOf(value));
  133. SimpleDateFormat dateFormat = new SimpleDateFormat(
  134. "dd/MM/yyyy");
  135. value = dateFormat.format(date);
  136. }
  137. //数字类型处理
  138. if(numberFlag){
  139. BigDecimal bd = new BigDecimal(value);
  140. value = bd.setScale(3,BigDecimal.ROUND_UP).toString();
  141. }
  142. rowlist.add(curCol, value);
  143. curCol++;
  144. }else {
  145. //如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法
  146. if (name.equals("row")) {
  147. rowReader.getRows(sheetIndex,curRow,rowlist);
  148. rowlist.clear();
  149. curRow++;
  150. curCol = 0;
  151. }
  152. }
  153. }
  154. public void characters(char[] ch, int start, int length)
  155. throws SAXException {
  156. //得到单元格内容的值
  157. lastContents += new String(ch, start, length);
  158. }
  159. }
  1. public class ExcelReaderUtil {
  2. //excel2003扩展名
  3. public static final String EXCEL03_EXTENSION = ".xls";
  4. //excel2007扩展名
  5. public static final String EXCEL07_EXTENSION = ".xlsx";
  6. /**
  7. * 读取Excel文件,可能是03也可能是07版本
  8. * @param excel03
  9. * @param excel07
  10. * @param fileName
  11. * @throws Exception
  12. */
  13. public static void readExcel(IRowReader reader,String fileName) throws Exception{
  14. // 处理excel2003文件
  15. if (fileName.endsWith(EXCEL03_EXTENSION)){
  16. Excel2003Reader excel03 = new Excel2003Reader();
  17. excel03.setRowReader(reader);
  18. excel03.process(fileName);
  19. // 处理excel2007文件
  20. } else if (fileName.endsWith(EXCEL07_EXTENSION)){
  21. Excel2007Reader excel07 = new Excel2007Reader();
  22. excel07.setRowReader(reader);
  23. excel07.process(fileName);
  24. } else {
  25. throw new  Exception("文件格式错误,fileName的扩展名只能是xls或xlsx。");
  26. }
  27. }
  28. }
  1. public interface IRowReader {
  2. /**业务逻辑实现方法
  3. * @param sheetIndex
  4. * @param curRow
  5. * @param rowlist
  6. */
  7. public  void getRows(int sheetIndex,int curRow, List<String> rowlist);
  8. }
  1. public class RowReader implements IRowReader{
  2. /* 业务逻辑实现方法
  3. * @see com.eprosun.util.excel.IRowReader#getRows(int, int, java.util.List)
  4. */
  5. public void getRows(int sheetIndex, int curRow, List<String> rowlist) {
  6. // TODO Auto-generated method stub
  7. System.out.print(curRow+" ");
  8. for (int i = 0; i < rowlist.size(); i++) {
  9. System.out.print(rowlist.get(i) + " ");
  10. }
  11. System.out.println();
  12. }
  13. }
  1. public class Main {
  2. public static void main(String[] args) throws Exception {
  3. IRowReader reader = new RowReader();
  4. //ExcelReaderUtil.readExcel(reader, "F://te03.xls");
  5. ExcelReaderUtil.readExcel(reader, "F://test07.xlsx");
  6. }
  7. }
  1. public class Excel2003Writer {
  2. /**
  3. * @param args
  4. */
  5. public static void main(String[] args) {
  6. try{
  7. System.out.println("开始写入excel2003....");
  8. writeExcel("tes2003.xls");
  9. System.out.println("写完xcel2003");
  10. } catch (IOException e) {
  11. }
  12. }
  13. /**
  14. * 写入excel并填充内容,一个sheet只能写65536行以下,超出会报异常,写入时建议使用AbstractExcel2007Writer
  15. * @param fileName
  16. * @throws IOException
  17. */
  18. public static void writeExcel(String fileName) throws IOException{
  19. // 创建excel2003对象
  20. Workbook wb = new HSSFWorkbook();
  21. // 设置文件放置路径和文件名
  22. FileOutputStream fileOut = new FileOutputStream(fileName);
  23. // 创建新的表单
  24. Sheet sheet = wb.createSheet("newsheet");
  25. // 创建新行
  26. for(int i=0;i<20000;i++){
  27. Row row = sheet.createRow(i);
  28. // 创建单元格
  29. Cell cell = row.createCell(0);
  30. // 设置单元格值
  31. cell.setCellValue(1);
  32. row.createCell(1).setCellValue(1+i);
  33. row.createCell(2).setCellValue(true);
  34. row.createCell(3).setCellValue(0.43d);
  35. row.createCell(4).setCellValue('d');
  36. row.createCell(5).setCellValue("");
  37. row.createCell(6).setCellValue("第七列"+i);
  38. row.createCell(7).setCellValue("第八列"+i);
  39. }
  40. wb.write(fileOut);
  41. fileOut.close();
  42. }
  43. }

  1. /**
  2. * 抽象excel2007读入器,先构建.xlsx一张模板,改写模板中的sheet.xml,使用这种方法
  3. * 写入.xlsx文件,不需要太大的内存
  4. *
  5. */
  6. public abstract class AbstractExcel2007Writer {
  7. private SpreadsheetWriter sw;
  8. /**
  9. * 写入电子表格的主要流程
  10. * @param fileName
  11. * @throws Exception
  12. */
  13. public void process(String fileName) throws Exception{
  14. // 建立工作簿和电子表格对象
  15. XSSFWorkbook wb = new XSSFWorkbook();
  16. XSSFSheet sheet = wb.createSheet("sheet1");
  17. // 持有电子表格数据的xml文件名 例如 /xl/worksheets/sheet1.xml
  18. String sheetRef = sheet.getPackagePart().getPartName().getName();
  19. // 保存模板
  20. FileOutputStream os = new FileOutputStream("template.xlsx");
  21. wb.write(os);
  22. os.close();
  23. // 生成xml文件
  24. File tmp = File.createTempFile("sheet", ".xml");
  25. Writer fw = new FileWriter(tmp);
  26. sw = new SpreadsheetWriter(fw);
  27. generate();
  28. fw.close();
  29. // 使用产生的数据替换模板
  30. File templateFile = new File("template.xlsx");
  31. FileOutputStream out = new FileOutputStream(fileName);
  32. substitute(templateFile, tmp, sheetRef.substring(1), out);
  33. out.close();
  34. //删除文件之前调用一下垃圾回收器,否则无法删除模板文件
  35. System.gc();
  36. // 删除临时模板文件
  37. if (templateFile.isFile()&&templateFile.exists()){
  38. templateFile.delete();
  39. }
  40. }
  41. /**
  42. * 类使用者应该使用此方法进行写操作
  43. * @throws Exception
  44. */
  45. public abstract void generate() throws Exception;
  46. public void beginSheet() throws IOException {
  47. sw.beginSheet();
  48. }
  49. public void insertRow(int rowNum) throws IOException {
  50. sw.insertRow(rowNum);
  51. }
  52. public void createCell(int columnIndex, String value) throws IOException {
  53. sw.createCell(columnIndex, value, -1);
  54. }
  55. public void createCell(int columnIndex, double value) throws IOException {
  56. sw.createCell(columnIndex, value, -1);
  57. }
  58. public void endRow() throws IOException {
  59. sw.endRow();
  60. }
  61. public void endSheet() throws IOException {
  62. sw.endSheet();
  63. }
  64. /**
  65. *
  66. * @param zipfile the template file
  67. * @param tmpfile the XML file with the sheet data
  68. * @param entry the name of the sheet entry to substitute, e.g. xl/worksheets/sheet1.xml
  69. * @param out the stream to write the result to
  70. */
  71. private static void substitute(File zipfile, File tmpfile, String entry,
  72. OutputStream out) throws IOException {
  73. ZipFile zip = new ZipFile(zipfile);
  74. ZipOutputStream zos = new ZipOutputStream(out);
  75. @SuppressWarnings("unchecked")
  76. Enumeration<ZipEntry> en = (Enumeration<ZipEntry>) zip.entries();
  77. while (en.hasMoreElements()) {
  78. ZipEntry ze = en.nextElement();
  79. if (!ze.getName().equals(entry)) {
  80. zos.putNextEntry(new ZipEntry(ze.getName()));
  81. InputStream is = zip.getInputStream(ze);
  82. copyStream(is, zos);
  83. is.close();
  84. }
  85. }
  86. zos.putNextEntry(new ZipEntry(entry));
  87. InputStream is = new FileInputStream(tmpfile);
  88. copyStream(is, zos);
  89. is.close();
  90. zos.close();
  91. }
  92. private static void copyStream(InputStream in, OutputStream out)
  93. throws IOException {
  94. byte[] chunk = new byte[1024];
  95. int count;
  96. while ((count = in.read(chunk)) >= 0) {
  97. out.write(chunk, 0, count);
  98. }
  99. }
  100. /**
  101. * 在写入器中写入电子表格
  102. *
  103. */
  104. public static class SpreadsheetWriter {
  105. private final Writer _out;
  106. private int _rownum;
  107. private static String LINE_SEPARATOR = System.getProperty("line.separator");
  108. public SpreadsheetWriter(Writer out) {
  109. _out = out;
  110. }
  111. public void beginSheet() throws IOException {
  112. _out.write("<?xml version=\"1.0\" encoding=\"GB2312\"?>"
  113. + "<worksheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
  114. _out.write("<sheetData>"+LINE_SEPARATOR);
  115. }
  116. public void endSheet() throws IOException {
  117. _out.write("</sheetData>");
  118. _out.write("</worksheet>");
  119. }
  120. /**
  121. * 插入新行
  122. *
  123. * @param rownum 以0开始
  124. */
  125. public void insertRow(int rownum) throws IOException {
  126. _out.write("<row r=\"" + (rownum + 1) + "\">"+LINE_SEPARATOR);
  127. this._rownum = rownum;
  128. }
  129. /**
  130. * 插入行结束标志
  131. */
  132. public void endRow() throws IOException {
  133. _out.write("</row>"+LINE_SEPARATOR);
  134. }
  135. /**
  136. * 插入新列
  137. * @param columnIndex
  138. * @param value
  139. * @param styleIndex
  140. * @throws IOException
  141. */
  142. public void createCell(int columnIndex, String value, int styleIndex)
  143. throws IOException {
  144. String ref = new CellReference(_rownum, columnIndex)
  145. .formatAsString();
  146. _out.write("<c r=\"" + ref + "\" t=\"inlineStr\"");
  147. if (styleIndex != -1)
  148. _out.write(" s=\"" + styleIndex + "\"");
  149. _out.write(">");
  150. _out.write("<is><t>"+XMLEncoder.encode(value)+"</t></is>");
  151. _out.write("</c>");
  152. }
  153. public void createCell(int columnIndex, String value)
  154. throws IOException {
  155. createCell(columnIndex, value, -1);
  156. }
  157. public void createCell(int columnIndex, double value, int styleIndex)
  158. throws IOException {
  159. String ref = new CellReference(_rownum, columnIndex)
  160. .formatAsString();
  161. _out.write("<c r=\"" + ref + "\" t=\"n\"");
  162. if (styleIndex != -1)
  163. _out.write(" s=\"" + styleIndex + "\"");
  164. _out.write(">");
  165. _out.write("<v>" + value + "</v>");
  166. _out.write("</c>");
  167. }
  168. public void createCell(int columnIndex, double value)
  169. throws IOException {
  170. createCell(columnIndex, value, -1);
  171. }
  172. public void createCell(int columnIndex, Calendar value, int styleIndex)
  173. throws IOException {
  174. createCell(columnIndex, DateUtil.getExcelDate(value, false),
  175. styleIndex);
  176. }
  177. }
  178. }
  1. public class Excel2007WriterImpl extends AbstractExcel2007Writer{
  2. /**
  3. * @param args
  4. * @throws Exception
  5. */
  6. public static void main(String[] args) throws Exception {
  7. // TODO Auto-generated method stub
  8. System.out.println("............................");
  9. long start = System.currentTimeMillis();
  10. //构建excel2007写入器
  11. AbstractExcel2007Writer excel07Writer = new Excel2007WriterImpl();
  12. //调用处理方法
  13. excel07Writer.process("F://test07.xlsx");
  14. long end = System.currentTimeMillis();
  15. System.out.println("....................."+(end-start)/1000);
  16. }
  17. /*
  18. * 可根据需求重写此方法,对于单元格的小数或者日期格式,会出现精度问题或者日期格式转化问题,建议使用字符串插入方法
  19. * @see com.excel.ver2.AbstractExcel2007Writer#generate()
  20. */
  21. @Override
  22. public void generate()throws Exception {
  23. //电子表格开始
  24. beginSheet();
  25. for (int rownum = 0; rownum < 100; rownum++) {
  26. //插入新行
  27. insertRow(rownum);
  28. //建立新单元格,索引值从0开始,表示第一列
  29. createCell(0, "中国<" + rownum + "!");
  30. createCell(1, 34343.123456789);
  31. createCell(2, "23.67%");
  32. createCell(3, "12:12:23");
  33. createCell(4, "2010-10-11 12:12:23");
  34. createCell(5, "true");
  35. createCell(6, "false");
  36. //结束行
  37. endRow();
  38. }
  39. //电子表格结束
  40. endSheet();
  41. }
  42. }
  1. public class XMLEncoder {
  2. private static final String[] xmlCode = new String[256];
  3. static {
  4. // Special characters
  5. xmlCode['\''] = "'";
  6. xmlCode['\"'] = """; // double quote
  7. xmlCode['&'] = "&"; // ampersand
  8. xmlCode['<'] = "<"; // lower than
  9. xmlCode['>'] = ">"; // greater than
  10. }
  11. /**
  12. * <p>
  13. * Encode the given text into xml.
  14. * </p>
  15. *
  16. * @param string the text to encode
  17. * @return the encoded string
  18. */
  19. public static String encode(String string) {
  20. if (string == null) return "";
  21. int n = string.length();
  22. char character;
  23. String xmlchar;
  24. StringBuffer buffer = new StringBuffer();
  25. // loop over all the characters of the String.
  26. for (int i = 0; i < n; i++) {
  27. character = string.charAt(i);
  28. // the xmlcode of these characters are added to a StringBuffer one by one
  29. try {
  30. xmlchar = xmlCode[character];
  31. if (xmlchar == null) {
  32. buffer.append(character);
  33. } else {
  34. buffer.append(xmlCode[character]);
  35. }
  36. } catch (ArrayIndexOutOfBoundsException aioobe) {
  37. buffer.append(character);
  38. }
  39. }
  40. return buffer.toString();
  41. }
  42. }