Excel文件(.xls和.xlsx)文件的读取总结

1、.xls和.xlsx的区别

(1)文件格式不同。xls 是一个特有的二进制格式,其核心结构是复合文档类型的结构,而 xlsx 的核心结构是 XML 类型的结构,采用的是基于 XML 的压缩方式,使其占用的空间更小。xlsx 中最后一个 x 的意义就在于此。

(2)版本不同。xls是excel2003及以前版本生成的文件格式,而xlsx是excel2007及以后版本生成的文件格式。

(3)兼容性不同。xlsx格式是向下兼容的,可兼容xls格式。

(4)读取方式,两种:使用导入jxl包或或者使用java中的poi(导入jxl包的形式,只能处理xls格式;使用java中的poi的话,可以使用poi中的HSSFWorkBook来处理xls文件,使用XSSFWrokBook或者SXSSFWorkBook来处理xlsx格式的文件)

 

2、记录一下HSSFWorkBook,XSSFWrokBook,SXSSFWorkBook的区别(参考:https://www.cnblogs.com/skyislimit/articles/10514719.html)

      用Java中的poi导出Excel时,我们需要考虑到Excel版本及数据量的问题。针对不同的Excel版本,要采用不同的工具类,如果使用错了,会出现错误信息。JavaPOI导出Excel有三种形式,分别是HSSFWorkbook、XSSFWorkbook和SXSSFWorkbook。

      HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls。是poi导出excel最常用的方式;但是此种方式的局限就是导出的行数至多为65535行,超出65536条后系统就会报错。此方式因为行数不足七万行所以一般不会发生内存不足的情况(OOM)

      XSSFWorkbook:是操作Excel2007后的版本,扩展名是.xlsx。这种形式的出现是为了突破HSSFWorkbook的65535行局限。其对应的是excel2007(1048576行,16384列)扩展名为“.xlsx”,最多可以导出104万行,不过这样就伴随着一个问题---OOM内存溢出,原因是你所创建的book、sheet、row和cell等此时是存在内存的并没有持久化。

      SXSSFWorkbook:是操作Excel2007后的版本,扩展名是.xlsx。从POI 3.8版本开始,提供了一种基于XSSF的低内存占用的SXSSF方式。对于大型excel文件的创建,一个关键问题就是,要确保不会内存溢出。其实,就算生成很小的excel(比如几Mb),它用掉的内存是远大于excel文件实际的size的。如果单元格还有各种格式(比如,加粗,背景标红之类的),那它占用的内存就更多了。对于大型excel的创建且不会内存溢出的,就只有SXSSFWorkbook了。它的原理很简单,用硬盘空间换内存(就像hash map用空间换时间一样)。SXSSFWorkbook是streaming版本的XSSFWorkbook,它只会保存最新的excel rows在内存里供查看,在此之前的excel rows都会被写入到硬盘里(Windows电脑的话,是写入到C盘根目录下的temp文件夹)。被写入到硬盘里的rows是不可见的/不可访问的。只有还保存在内存里的才可以被访问到。

 

3、具体代码实现

(1)使用HSSFWorkBook来读取excel文件(.xls格式)

几点注意:

a、使用HSSFWorkBook不可读取xlsx格式,否则报错如下:

org.apache.poi.poifs.filesystem.OfficeXmlFileException: The supplied data appears to be in the Office 2007+ XML. You are calling the part of POI that deals with OLE2 Office Documents. You need to call a different part of POI to process this data (eg XSSF instead of HSSF)

b、getFirstRowNum获取第一行的行号,getLastRowNum获取最后一行的行号;

      Row row = sheet.getRow(i)获取第i行

      row.getFirstCellNum()获取row行的第一列列号, row.getLastCellNum()获取row行的最后一列的列号

      row.getCell(j).getNumericCellValue()读取数值类型的值, row.getCell(j).getStringCellValue()读取字符串类型值

c、在遍历行或者列的时候,注意最后一行或者一列是读取不到的,不要用等于号,否则空指针异常。i < sheet.getLastRowNum()而不是i < =sheet.getLastRowNum()。

package com.netease.work.video_download.excel;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author wangql
 * @date 2020/6/13  7:47
 * @描述
 */
public class HSSFWorkBookTest {
    public static void main(String[] args) {
        File file = new File("B:\\seckill\\test.xls");
        try {
            FileInputStream fis = new FileInputStream(file.getAbsolutePath());
            HSSFWorkbook hwb = new HSSFWorkbook(fis);
            // int rows = hwb.getNumberOfSheets();
            Sheet sheet = hwb.getSheetAt(0);
            // 循环遍历每一行
            for(int i = sheet.getFirstRowNum(); i < sheet.getLastRowNum(); i++){
                // 循环遍历每一列
                Row row = sheet.getRow(i);
                for(int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++){
                    if(row.getCell(j).getCellType() == CellType.NUMERIC){
                        System.out.print((int)row.getCell(j).getNumericCellValue()+"   ");
                    }else if(row.getCell(j).getCellType() == CellType.STRING){
                        System.out.print(row.getCell(j).getStringCellValue()+"   ");
                    }

                }
                System.out.println();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

(2)使用XSSFWorkBook来读取excel文件(.xlsx格式)

几点注意:

a、使用XSSFWorkBook不可读取xls格式,否则报错如下:

org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF)

b、getFirstRowNum获取第一行的行号,getLastRowNum获取最后一行的行号;

      Row row = sheet.getRow(i)获取第i行

      row.getFirstCellNum()获取row行的第一列列号, row.getLastCellNum()获取row行的最后一列的列号

      row.getCell(j).getNumericCellValue()读取数值类型的值, row.getCell(j).getStringCellValue()读取字符串类型值

c、在遍历行或者列的时候,注意最后一行或者一列是读取不到的,不要用等于号,否则空指针异常。i < sheet.getLastRowNum()而不是i < =sheet.getLastRowNum()。

package com.netease.work.video_download.excel;

import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author wangql
 * @date 2020/6/13  7:48
 * @描述
 */
public class XSSFWorkBookTest {
    public static void main(String[] args) {
        File file = new File("B:\\seckill\\test.xlsx");
        try {
            FileInputStream fis = new FileInputStream(file.getAbsolutePath());
            XSSFWorkbook swb = new XSSFWorkbook(fis);
            Sheet sheet = swb.getSheetAt(0);
            for(int i = sheet.getFirstRowNum(); i < sheet.getLastRowNum(); i++){
                Row row = sheet.getRow(i);
                for(int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++){
                    if(row.getCell(j).getCellType() == CellType.NUMERIC){
                        System.out.print((int)row.getCell(j).getNumericCellValue()+"   ");
                    }else if(row.getCell(j).getCellType() == CellType.STRING){
                        System.out.print(row.getCell(j).getStringCellValue()+"   ");
                    }

                }
                System.out.println();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

(3)使用SXSSFWorkBook来读取excel文件(.xlsx格式)

几点注意:

a、使用SXSSFWorkBook不可读取xls格式,否则报错如下:

org.apache.poi.openxml4j.exceptions.OLE2NotOfficeXmlFileException: The supplied data appears to be in the OLE2 Format. You are calling the part of POI that deals with OOXML (Office Open XML) Documents. You need to call a different part of POI to process this data (eg HSSF instead of XSSF)

b、getFirstRowNum获取第一行的行号,getLastRowNum获取最后一行的行号;

      Row row = sheet.getRow(i)获取第i行

      row.getFirstCellNum()获取row行的第一列列号, row.getLastCellNum()获取row行的最后一列的列号

      row.getCell(j).getNumericCellValue()读取数值类型的值, row.getCell(j).getStringCellValue()读取字符串类型值

c、在遍历行或者列的时候,注意最后一行或者一列是读取不到的,不要用等于号,否则空指针异常。i < sheet.getLastRowNum()而不是i < =sheet.getLastRowNum()。

package com.netease.work.video_download.excel;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author wangql
 * @date 2020/6/13  7:48
 * @描述
 */
public class SXSSFWorkBookTest {
    public static void main(String[] args) {
        File file = new File("B:\\seckill\\test.xlsx");
        try {
            FileInputStream fis = new FileInputStream(file.getAbsolutePath());
            XSSFWorkbook swb = new XSSFWorkbook(fis);
            Sheet sheet = swb.getSheetAt(0);
            for(int i = sheet.getFirstRowNum(); i < sheet.getLastRowNum(); i++){
                Row row = sheet.getRow(i);
                for(int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++){
                    if(row.getCell(j).getCellType() == CellType.NUMERIC){
                        System.out.print((int)row.getCell(j).getNumericCellValue()+"   ");
                    }else if(row.getCell(j).getCellType() == CellType.STRING){
                        System.out.print(row.getCell(j).getStringCellValue()+"   ");
                    }

                }
                System.out.println();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

3、总结

(1)HSSFWorkBook,只能读取xls格式文件;XSSFWorkBook和SXSSFWorkBook只能读取xlsx格式的文件,根据自己的 文件格式选择使用不同的类型

(2)HSSFWorkBook处理excel格式的文件行数最大65535行,XSSFWorkBook能够处理最大1048576行,16384列的文件

(3)方法总结:

         a、一个excel文件中可以有多个sheet,获取所有sheet的过程,先使用getNumberOfSheets()获取所有sheet的数量,然后使用getSheetAt(index)的形式,类似于数组获取值的方式来获取每个sheet

         b、getFirstRowNum、getLastRowNum、getRow(i)、row.getFirstCellNum()、row.getLastCellNum()、getCellType()、getNumericCellValue、getStringCellValue等,见上述代码。注意获取单元格数据时候最好进行格式判断,根据不同的格式,选择使用不同的获取数据的格式,如果是CellType.NUMERIC类型,则使用getNumericCellValue获取数据;如果是CellType.STRING类型,则使用getStringCellValue读取数据。CellType.NUMERIC和CellType.STRING是poi依赖包中自定义的枚举类,可以自己查看。判断过程如下:

if(row.getCell(j).getCellType() == CellType.NUMERIC){
    System.out.print((int)row.getCell(j).getNumericCellValue()+"   ");
}else if(row.getCell(j).getCellType() == CellType.STRING){
    System.out.print(row.getCell(j).getStringCellValue()+"   ");
}

 

4、上述代码写在一个maven项目总,pom文件如下,几个核心依赖红色标出。



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.3.0.RELEASE
         
    
    com.netease.work
    video_download
    0.0.1-SNAPSHOT
    video_download
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
            
                
                    org.junit.vintage
                    junit-vintage-engine
                
            
        
        
            org.apache.poi
            poi
            4.1.2
        
        
            org.apache.poi
            poi-ooxml
            4.1.2
        
        
        
            org.apache.poi
            poi-scratchpad
            4.1.2
        
        
        
            org.apache.xmlbeans
            xmlbeans
            3.1.0
        
        
        
            org.apache.poi
            poi-ooxml-schemas
            4.1.2
        
        
            com.google.guava
            guava
            29.0-jre
        
    
    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

 

5、除了使用poi中的HSSFWorkBook来读取xls格式的文件外,还可以通过jxl包来实现对xls文件的读取。可以通过手动下载jxlbao或者引入依赖的方式。直接贴代码,不做额外解释。

package com.netease.work.video_download.excel;

import jxl.Sheet;
import jxl.Workbook;
import java.io.File;
import java.io.FileInputStream;

/**
 * @author wangql
 * @date 2020/6/13  7:47
 * @描述
 */
public class WorkBookTest {
    public static void main(String[] args) {
        File file = new File("B:\\seckill\\test.xlsx");
        try {
            FileInputStream fis = new FileInputStream(file.getAbsolutePath());
            Workbook workBook = Workbook.getWorkbook(fis);
            // getNumberOfSheets是获取一个excel文件中的sheet数量,有多个sheet时可以通过循环遍历读取
            // int sheetNums = workBook.getNumberOfSheets();
            // getSheet通过下标读取指定的sheet,如果只有一个,则直接getSheet(0)获取此sheet
            Sheet sheet = workBook.getSheet(0);
            // 循环遍历读取此sheet下的各行数据
            for(int i = 0; i < sheet.getRows(); i++){
                // 循环读取一行数据中的各列数据
                for(int j = 0; j < sheet.getColumns(); j++){
                    // 读取单元格i行j列的数据,注意getCell参数中,第一个是列,第二个是行
                    System.out.print(sheet.getCell(j,i).getContents()+"   ");
                }
                System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

 

你可能感兴趣的:(Excel文件(.xls和.xlsx)文件的读取总结)