JAVA操作excel总结

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_24334403/article/details/79121463

目前主要有两种常用的方式,jxl和POI。因为POI功能更加强大,面对大量数据时操作性能更加优于jxl,因此,在工作中一般使用POI来操作excel。

      POI是Apache下的开放源码函数库,POI提供了一系列的api来供java程序员对Microsoft Office格式的文档提供读写功能。

      由于excel2003(.xls)与excel2007(.xlsx)以及之后版本底层的实现方式不同,因此POI对不同版本的excel操作方式也不尽相同。

  • 1.新建excel并写入:

   

Workbook wwb = new XSSFWorkbook();//创建excel工作簿   excel2003以及之前版本请使用HSSFWorkbook
  Sheet sheet = wwb.createSheet( "sheet1" );// 创建sheet  若有多页sheet页面可创建多个
  Row row = sheet.createRow( 0 );//创建行 0代表第一行
  row1.createCell( 0 ).setCellValue( '单元格');//创建单元格并赋值 0代表当前行的第一个单元格}}}
  //Workbook提供write方法,可以将当前工作空间写出到指定的地方。


 

  • 2.读取excel
   Workbook wwb = new XSSFWorkbook(excel.getInputStream());//将指定excel文件转化为工作空间
  Sheet sheet = wwb.getSheetAt( 0 );// 获取第一个sheet页
  Row row = sheet.getRow( 0 );//获取当前页的一行
  //获取当前行的第一个单元格   excel支持多种数据类型,可以使用 getCellType()方法来获取当前单元格数据类型
  row1.getCell( 0 );
  • 3.有关excel性能的问题。

       在写入excel时XSSFWorkbook采用的是将所有数据处理完成后一次写入excel文件,当写入的文件数据量较大时,特别是一次写入十几万条数据时,很容易发生内存溢出,在数据量很庞大的情况下,调整jvm内存并不是最优的办法,因此,POI在3.8版本增加了对于超大数据量的特定api(这种api只能针对exel2007及以后版本使用),SXSSFWorkbook的使用方式 很简单,直接创建Workbook wwb = new XSSFWorkbook(100);//100代表每当有100条数据时就将内存中的数据写入到指定的excel中
这样就避免了处理很大数据量内存溢出的问题。       同理,在读取excel的时候,XSSFWorkbook也是将所有数据全部读取到内存中,才开始处理,因此,当数据量较大时也会发生内存溢出事件。因此,POI也提供了对于读取超大数据量的api(此方法也只能用于excel2007及以后版本,2007版本以后excel底层使用xml)。此方法采用的是一行一行读取exel,因此也不会发生内存溢出。读取代码demo如下:

public class ExcelEventParser {
  
  private String fileName;//文件名
  private SheetContentsHandler handler;//读取文件
  public ExcelEventParser(String fileName){
     this.fileName = fileName;
  }
  
  public ExcelEventParser setHandler(SheetContentsHandler handler){
     this.handler = handler;
     return this ;
  }
  
  public void parse(){
      OPCPackage pkg = null ;
      InputStream sheetInputStream = null ;
     try{
         pkg = OPCPackage.open(fileName,PackageAccess.READ);//打开一个含有读权限的包
        XSSFReader xssfReader = new XSSFReader(pkg);//获取xlsx文件
        
         StylesTable stylesTable = xssfReader.getStylesTable();//
        ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(pkg);
         sheetInputStream = xssfReader.getSheetsData().next();
        
         processSheet(stylesTable,strings,sheetInputStream);
     }catch(Exception e){
         e.printStackTrace();
        throw new RuntimeException(e.getMessage(),e);
     }finally {
        if(sheetInputStream != null ){
           try {
               sheetInputStream.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
        }
        if(pkg != null ){
           try {
               pkg.close();
           } catch (IOException e) {
               e.printStackTrace();
           }
        }
     }
  }
  
  private void processSheet(StylesTable styles,ReadOnlySharedStringsTable strings,InputStream sheetInputStream)
        throws SAXException, ParserConfigurationException, IOException{
      XMLReader sheetParser = SAXHelper.newXMLReader();
     if(handler != null ){
         sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, handler, false));
     }else{
         sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings,new SimpleSheetContentsHandler(), false));
     }
      sheetParser.parse(new InputSource(sheetInputStream));
  }
  public static class SimpleSheetContentsHandler implements SheetContentsHandler{  
      protected List<String> row = new LinkedList<>();
      @Override  
      public void startRow(int rowNum) {  
           row.clear();  
      }  
      @Override  
      public void endRow(int rowNum) {  
           System.err.println(rowNum + " : " + row);  
      }  
      @Override  
      public void cell(String cellReference, String formattedValue, XSSFComment comment) {  
           row.add(formattedValue);  
      }  
      @Override  
      public void headerFooter(String text, boolean isHeader, String tagName) {       
      }  
  }
  public static void main(String[] args) throws Throwable{  
      long start = System.currentTimeMillis();  
      final List<List<String>> table = new ArrayList<>();  
      new ExcelEventParser("/Users/niulj/Desktop/123.xlsx").setHandler(new SimpleSheetContentsHandler(){  
          @Override  
          public void endRow(int rowNum) {  
              if(rowNum == 0){  
                  // todo 对表头的读取以及处理
              }else {  
                  row.get(0);//对当前行的第一个单元格进行读取
              }  
          }  
      }).parse();        
  }
}


      另外,我们在读取一些数,比如手机号,如果按照数字读取需要注意指定格式(DecimalFormat df = new DecimalFormat("#.#"))来处理读取数据含有小数位的问题,另外在读取单元格的时候最好判断单元格类型。此外会遇到各种看到的excel行数与实际程序读取的行数不同的问题,这种问题一般都是由于使用者删除excel时没有完全删除该行,因此在最好在读取行的时候添加是否是空行的校验。

       对于上千万数据的读取与导出,由于excel目前新版最大支持100万左右,因此,若真的想一个excel读取,可以采用多sheet的方式,导出时也可以采用这种方式处理,但是若远程导出,文件较大时可以在服务器端先压缩打包,然后将打包文件发送给客户端。打包时可以将excel拆分为多个。

猜你喜欢

转载自blog.csdn.net/qq_24334403/article/details/79121463
今日推荐