跳转至

Java读取Excel文件:从入门到实践

简介

在Java开发中,读取Excel文件是一个常见的需求。无论是处理业务数据、进行数据统计分析还是进行数据迁移,都可能需要从Excel文件中提取信息。本文将详细介绍Java读取Excel文件的相关知识,包括基础概念、使用方法、常见实践以及最佳实践,帮助读者全面掌握这一技术。

目录

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

基础概念

Excel文件格式

Excel文件有多种格式,常见的有.xls(Excel 97-2003格式)和.xlsx(Excel 2007及以上版本格式)。.xls是一种二进制文件格式,而.xlsx是基于XML的压缩文件格式。理解这些文件格式的差异对于选择合适的Java库和处理方式非常重要。

Java操作Excel的常用库

  1. Apache POI:这是一个广泛使用的Java库,提供了丰富的API来操作各种Microsoft Office格式文件,包括Excel。它支持读取、写入和修改Excel文件,并且对不同版本的Excel文件都有良好的支持。
  2. EasyExcel:EasyExcel是一个轻量级的Java库,专注于简化Excel文件的读写操作。它在性能和易用性方面表现出色,特别适合处理大数据量的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/file.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.1.1</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.event.AnalysisEventListener;

import java.util.List;

public class EasyExcelExample {
    public static void main(String[] args) {
        String filePath = "path/to/your/file.xlsx";
        EasyExcel.read(filePath, ExcelData.class, new AnalysisEventListener<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/file.xls";
        String xlsxFilePath = "path/to/your/file.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枚举来判断单元格的数据类型,并通过相应的方法获取数据。示例代码如下:

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 HandleCellDataTypes {
    public static void main(String[] args) {
        String filePath = "path/to/your/file.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();
        }
    }
}

读取特定单元格和行

可以通过指定行号和列号来读取特定的单元格。示例代码如下:

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 ReadSpecificCellsAndRows {
    public static void main(String[] args) {
        String filePath = "path/to/your/file.xlsx";
        try (FileInputStream fis = new FileInputStream(new File(filePath));
             Workbook workbook = new XSSFWorkbook(fis)) {

            Sheet sheet = workbook.getSheetAt(0);
            // 读取第2行第3列的单元格
            Row row = sheet.getRow(1);
            Cell cell = row.getCell(2);
            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的AnalysisEventListener)可以显著提高性能,因为它不会一次性将整个文件加载到内存中。
  • 减少不必要的对象创建:在读取Excel文件时,尽量减少不必要的对象创建,以降低内存消耗。例如,可以复用已有的对象来存储数据。

错误处理与日志记录

  • 完善错误处理机制:在读取Excel文件时,可能会遇到各种错误,如文件格式错误、单元格数据类型不匹配等。应完善错误处理机制,确保程序在遇到错误时能够优雅地处理,而不是崩溃。
  • 记录详细日志:记录详细的日志信息,以便在出现问题时能够快速定位和解决。可以使用日志框架(如Log4j、SLF4J等)来记录日志。

内存管理

  • 及时释放资源:在读取完Excel文件后,及时关闭相关的输入流和工作簿对象,以释放资源。可以使用try-with-resources语句来确保资源的正确释放。

小结

本文详细介绍了Java读取Excel文件的相关知识,包括基础概念、使用方法、常见实践以及最佳实践。通过学习这些内容,读者可以根据自己的需求选择合适的库和方法来读取Excel文件,并在实际项目中优化性能、处理错误和管理内存。希望本文能够帮助读者更好地掌握Java读取Excel文件这一技术。

参考资料