跳转至

Java读取Excel文件:从基础到最佳实践

简介

在Java开发中,处理Excel文件是一项常见的任务。无论是从Excel文件中提取数据进行业务逻辑处理,还是将数据导入到数据库中,掌握如何使用Java读取Excel文件都是非常重要的技能。本文将详细介绍Java读取Excel文件的基础概念、使用方法、常见实践以及最佳实践,帮助读者在实际项目中高效地处理Excel文件。

目录

  1. 基础概念
    • Excel文件格式
    • Java操作Excel的常用库
  2. 使用方法
    • 使用Apache POI读取Excel文件
    • 使用EasyExcel读取Excel文件
  3. 常见实践
    • 读取不同版本Excel文件
    • 处理Excel中的各种数据类型
    • 读取特定单元格和区域的数据
  4. 最佳实践
    • 性能优化
    • 错误处理与日志记录
    • 代码结构与可维护性
  5. 小结
  6. 参考资料

基础概念

Excel文件格式

Excel文件有多种格式,常见的有 .xls.xlsx.xls 是Excel 97-2003的文件格式,基于BIFF(Binary Interchange File Format);.xlsx 是Excel 2007及更高版本的文件格式,基于Office Open XML标准,本质上是一个压缩的XML文件。

Java操作Excel的常用库

  • Apache POI:一个开源的Java库,提供了操作各种微软Office格式文件的API,包括Excel。它支持读取和写入 .xls.xlsx 文件,功能强大且灵活,但使用起来相对复杂。
  • EasyExcel:阿里巴巴开源的一个轻量级Java Excel处理框架,基于POI进行封装,简化了POI的使用,提高了开发效率,尤其适用于大数据量的Excel处理。

使用方法

使用Apache POI读取Excel文件

  1. 添加依赖pom.xml 中添加Apache POI的依赖:
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.0.0</version>
</dependency>
  1. 读取Excel文件示例
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ApachePOIExample {
    public static void main(String[] args) {
        String filePath = "path/to/your/excelFile.xlsx";
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            for (Row row : sheet) {
                for (Cell cell : row) {
                    CellType cellType = cell.getCellType();
                    if (cellType == CellType.STRING) {
                        System.out.print(cell.getStringCellValue() + "\t");
                    } else if (cellType == CellType.NUMERIC) {
                        if (DateUtil.isCellDateFormatted(cell)) {
                            System.out.print(cell.getDateCellValue() + "\t");
                        } else {
                            System.out.print(cell.getNumericCellValue() + "\t");
                        }
                    } else if (cellType == CellType.BOOLEAN) {
                        System.out.print(cell.getBooleanCellValue() + "\t");
                    } else {
                        System.out.print(cell.toString() + "\t");
                    }
                }
                System.out.println();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

使用EasyExcel读取Excel文件

  1. 添加依赖pom.xml 中添加EasyExcel的依赖:
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>3.3.2</version>
</dependency>
  1. 创建数据模型类
import com.alibaba.excel.annotation.ExcelProperty;

public class ExcelData {
    @ExcelProperty("列1")
    private String column1;

    @ExcelProperty("列2")
    private String column2;

    // getters and setters
    public String getColumn1() {
        return column1;
    }

    public void setColumn1(String column1) {
        this.column1 = column1;
    }

    public String getColumn2() {
        return column2;
    }

    public void setColumn2(String column2) {
        this.column2 = column2;
    }
}
  1. 读取Excel文件示例
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;

import java.util.List;

public class EasyExcelExample {
    public static void main(String[] args) {
        String filePath = "path/to/your/excelFile.xlsx";
        EasyExcel.read(filePath, ExcelData.class, new ReadListener<ExcelData>() {
            @Override
            public void invoke(ExcelData data, AnalysisContext context) {
                System.out.println(data.getColumn1() + "\t" + data.getColumn2());
            }

            @Override
            public void doAfterAllAnalysed(AnalysisContext context) {
                System.out.println("读取完成");
            }
        }).sheet().doRead();
    }
}

常见实践

读取不同版本Excel文件

Apache POI可以通过不同的类来处理不同版本的Excel文件。对于 .xls 文件,使用 HSSFWorkbook;对于 .xlsx 文件,使用 XSSFWorkbook。示例如下:

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class ReadDifferentExcelVersions {
    public static void main(String[] args) {
        String xlsFilePath = "path/to/your/excelFile.xls";
        String xlsxFilePath = "path/to/your/excelFile.xlsx";

        try (FileInputStream xlsFis = new FileInputStream(new File(xlsFilePath));
             Workbook xlsWorkbook = new HSSFWorkbook(xlsFis)) {
            // 处理.xls文件
        } catch (IOException e) {
            e.printStackTrace();
        }

        try (FileInputStream xlsxFis = new FileInputStream(new File(xlsxFilePath));
             Workbook xlsxWorkbook = new XSSFWorkbook(xlsxFis)) {
            // 处理.xlsx文件
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

处理Excel中的各种数据类型

在读取Excel数据时,需要处理不同的数据类型,如字符串、数字、日期、布尔值等。Apache POI提供了 CellType 枚举来判断单元格的数据类型,并通过相应的方法获取数据。示例代码见前面的Apache POI读取示例。

读取特定单元格和区域的数据

可以通过指定行号和列号来读取特定单元格的数据。例如,读取第2行第3列的单元格数据:

import org.apache.poi.ss.usermodel.Cell;
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;
import java.io.IOException;

public class ReadSpecificCell {
    public static void main(String[] args) {
        String filePath = "path/to/your/excelFile.xlsx";
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             XSSFWorkbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            Row row = sheet.getRow(1); // 第2行
            Cell cell = row.getCell(2); // 第3列
            if (cell != null) {
                CellType cellType = cell.getCellType();
                if (cellType == CellType.STRING) {
                    System.out.println(cell.getStringCellValue());
                } else if (cellType == CellType.NUMERIC) {
                    if (DateUtil.isCellDateFormatted(cell)) {
                        System.out.println(cell.getDateCellValue());
                    } else {
                        System.out.println(cell.getNumericCellValue());
                    }
                } else if (cellType == CellType.BOOLEAN) {
                    System.out.println(cell.getBooleanCellValue());
                } else {
                    System.out.println(cell.toString());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最佳实践

性能优化

  • 使用流式读取:对于大数据量的Excel文件,使用EasyExcel的流式读取可以减少内存占用。例如,在EasyExcel示例中,通过实现 ReadListener 接口来逐行处理数据,而不是一次性将所有数据加载到内存中。
  • 关闭资源:在使用完 FileInputStreamWorkbook 等资源后,及时关闭以释放资源。可以使用 try-with-resources 语句来确保资源自动关闭。

错误处理与日志记录

在读取Excel文件时,可能会遇到各种异常,如文件不存在、格式错误等。应该进行适当的错误处理,并记录日志以便排查问题。可以使用 try-catch 块捕获异常,并使用日志框架(如Log4j或SLF4J)记录错误信息。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ErrorHandlingExample {
    private static final Logger logger = LoggerFactory.getLogger(ErrorHandlingExample.class);

    public static void main(String[] args) {
        String filePath = "path/to/your/excelFile.xlsx";
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             // 这里假设使用Apache POI
             org.apache.poi.ss.usermodel.Workbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(fis)) {
            // 处理Excel文件
        } catch (IOException e) {
            logger.error("读取Excel文件时发生错误", e);
        }
    }
}

代码结构与可维护性

  • 封装逻辑:将读取Excel文件的逻辑封装到独立的方法或类中,提高代码的可读性和可维护性。例如,可以创建一个专门的 ExcelReader 类,将读取Excel文件的方法都放在这个类中。
  • 使用配置文件:将Excel文件路径等配置信息放在配置文件中,方便在不同环境下进行调整,而不需要修改代码。可以使用 Properties 类或其他配置管理工具(如Spring的 @ConfigurationProperties)来读取配置文件。

小结

本文详细介绍了Java读取Excel文件的相关知识,包括基础概念、使用方法、常见实践以及最佳实践。通过学习这些内容,读者可以根据项目需求选择合适的库和方法来高效地读取Excel文件,并在性能优化、错误处理和代码结构等方面遵循最佳实践,提高代码的质量和稳定性。

参考资料