如何使用 Java 灵活读取 Excel 内容?

在日常工作和学习中,我们经常需要从 Excel 文件中读取数据。对于少量数据,手动复制和粘贴可能是可行的,但是对于大量的数据,这种方法会变得非常低效。在这种情况下,使用 Java 程序自动读取 Excel 文件中的数据将是更好的选择。

 

本教程将介绍如何使用 Java 程序读取 Excel 文件中的数据,包括以下几个方面:

 

了解 Excel 文件格式

选择 Java 的 Excel 文件读取库

读取 Excel 文件中的数据

处理 Excel 文件中的不同数据类型

使用 Java 程序导出 Excel 文件

让我们开始吧!

 

1、了解 Excel 文件格式

在开始编写 Java 程序读取 Excel 文件之前,我们需要了解 Excel 文件格式。Excel 文件是基于 Microsoft 的 OLE2 格式的,这个格式将文件组织成一系列的 “容器” 和 “对象”。Excel 文件的主要容器是 Workbook,它包含一个或多个 Sheet。每个 Sheet 包含一组行和列,这些行和列组成了一个二维的单元格数组。每个单元格可以包含文本、数字、日期、布尔值等不同的数据类型。

 

2、选择 Java 的 Excel 文件读取库

在 Java 中,有多个库可以用于读取 Excel 文件。这些库包括 Apache POI、JExcelApi、EasyXLS、JXL 等。在本教程中,我们将使用 Apache POI 库。

 

Apache POI 是一个 Java API,用于操作 Microsoft 文档格式,包括 Word、Excel 和 PowerPoint。它提供了一组 Java 类,可以用于创建、读取和修改 Microsoft 文档。

 

3、读取 Excel 文件中的数据

在本节中,我们将演示如何使用 Apache POI 库读取 Excel 文件中的数据。

 

在开始之前,我们需要将 Apache POI 库添加到项目的依赖中。您可以通过 Maven 或 Gradle 等构建工具将它们添加到项目中。

 

以下是 Maven 项目的 pom.xml 文件中添加 Apache POI 库的示例代码:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>4.1.2</version>
</dependency>

以下是 Gradle 项目的 build.gradle 文件中添加 Apache POI 库的示例代码:

dependencies {
    implementation 'org.apache.poi:poi:4.1.2'
}

接下来,我们将演示如何使用 Apache POI 库读取 Excel 文件中的数据。

 

首先,我们需要创建一个 Workbook 对象,该对象表示整个 Excel 文件。在 Apache POI 中,Workbook 对象有三种不同的类型:HSSFWorkbook 表示一个 .xls 文件,XSSFWorkbook 表示一个 .xlsx 文件,SXSSFWorkbook 表示一个大型 .xlsx 文件。我们可以使用 WorkbookFactory.create() 方法根据文件的类型创建一个 Workbook 对象。以下是创建一个 XSSFWorkbook 对象的示例代码:

 

FileInputStream file = new FileInputStream(new File(“path/to/excel/file.xlsx”));

Workbook workbook = WorkbookFactory.create(file);

接下来,我们可以获取一个 Sheet 对象,该对象表示 Excel 文件中的一个工作表。在 Apache POI 中,Sheet 对象由 Workbook 对象的 getSheet() 方法返回。以下是获取名为 “Sheet1” 的 Sheet 对象的示例代码:

 

Sheet sheet = workbook.getSheet(“Sheet1”);

一旦我们获取了 Sheet 对象,我们就可以遍历其中的每一行和每一列,以读取其中的单元格数据。以下是遍历 Sheet 对象中的所有单元格并输出单元格值的示例代码:

Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
    Row row = rowIterator.next();
    Iterator<Cell> cellIterator = row.cellIterator();
    while (cellIterator.hasNext()) {
        Cell cell = cellIterator.next();
        switch (cell.getCellType()) {
            case STRING:
                System.out.print(cell.getStringCellValue() + "\t");
                break;
            case NUMERIC:
                System.out.print(cell.getNumericCellValue() + "\t");
                break;
            case BOOLEAN:
                System.out.print(cell.getBooleanCellValue() + "\t");
                break;
            default:
                System.out.print("\t");
        }
    }
    System.out.println();
}

上述代码中,我们使用了一个嵌套的迭代器来遍历每一行和每一列。在每个单元格中,我们使用 switch 语句根据不同的数据类型执行不同的操作。

 

4、处理 Excel 文件中的不同数据类型

在 Excel 文件中,单元格可以包含不同的数据类型,包括字符串、数字、日期和布尔值等。当我们读取单元格中的数据时,我们需要知道单元格中的数据类型,以正确地处理它们。

 

在 Apache POI 中,我们可以使用 Cell.getCellType() 方法获取单元格的数据类型。该方法返回 CellType 枚举类型的值,可以使用 switch 语句根据不同的枚举值执行不同的操作。

 

以下是使用 switch 语句处理不同数据类型的示例代码:

switch (cell.getCellType()) {
    case STRING:
        System.out.print(cell.getStringCellValue() + "\t");
        break;
    case NUMERIC:
        if (DateUtil.isCellDateFormatted(cell)) {
            System.out.print(cell.getDateCellValue() + "\t");
        } else {
            System.out.print(cell.getNumericCellValue() + "\t");
        }
        break;
    case BOOLEAN:
        System.out.print(cell.getBooleanCellValue() + "\t");
        break;
    default:
        System.out.print("\t");
}

在上述示例代码中,我们首先检查单元格的数据类型是否为字符串。如果是字符串,我们使用 getStringCellValue() 方法获取字符串值。如果单元格的数据类型为数字,我们还需要检查单元格是否包含日期。如果是日期,我们使用 getDateCellValue() 方法获取日期值,否则我们使用 getNumericCellValue() 方法获取数字值。

 

5、使用 Java 程序导出 Excel 文件

除了读取 Excel 文件中的数据外,我们还可以使用 Java 程序创建和导出 Excel 文件。Apache POI 提供了 HSSFWorkbook 和 XSSFWorkbook 两个类,用于创建和操作 Excel 文件。

 

HSSFWorkbook 类用于操作旧版的 .xls 格式的 Excel 文件,而 XSSFWorkbook 类用于操作新版的 .xlsx 格式的 Excel 文件。我们可以根据需要选择合适的类来创建和导出 Excel 文件。

 

以下是创建和导出 Excel 文件的一般步骤:

 

创建一个 Workbook 对象,表示整个 Excel 文件。

创建一个 Sheet 对象,表示 Excel 文件中的一个工作表。

创建 Row 和 Cell 对象,表示 Excel 文件中的行和列。

为每个单元格设置数据和样式。

将 Workbook 对象写入文件或输出流中。

下面,让我们来看一些示例代码,演示如何使用 Java 程序创建和导出 Excel 文件。

 

创建一个 XSSFWorkbook 对象

以下是创建一个 XSSFWorkbook 对象的示例代码:

Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet("Sheet1");

创建行和单元格

以下是创建行和单元格的示例代码:

Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("Hello, World!");

设置单元格样式

在 Excel 文件中,我们可以为单元格设置不同的样式,包括字体、颜色、对齐方式等。以下是设置单元格样式的示例代码:

CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setBold(true);
style.setFont(font);
cell.setCellStyle(style);

在上述示例代码中,我们首先使用 createCellStyle() 方法创建一个单元格样式对象。然后,我们使用 createFont() 方法创建一个字体对象,并设置其属性。最后,我们将样式应用于单元格。

 

导出 Excel 文件

导出 Excel 文件时,我们可以将 Workbook 对象写入文件或输出流中。以下是将 Workbook 对象写入文件的示例代码:

FileOutputStream fileOut = new FileOutputStream("path/to/excel/file.xlsx");
workbook.write(fileOut);
fileOut.close();

在上述示例代码中,我们首先使用 FileOutputStream 类创建一个文件输出流对象。然后,我们使用 write() 方法将 Workbook 对象写入文件中。最后,我们关闭文件输出流。

 

除了写入文件,我们还可以将 Workbook 对象输出到网络流中,以便在浏览器中下载 Excel 文件。以下是将 Workbook 对象输出到网络流中的示例代码:

response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-Disposition", "attachment; filename=\"excel_file.xlsx\"");
OutputStream outputStream = response.getOutputStream();
workbook.write(outputStream);
outputStream.close();

在上述示例代码中,我们首先设置 HTTP 响应的内容类型和文件名。然后,我们使用 getOutputStream() 方法获取网络输出流对象。最后,我们使用 write() 方法将 Workbook 对象写入网络流中,并关闭输出流。

 

完整示例代码

 

下面是一个完整的示例代码,演示如何使用 Java 程序读取和导出 Excel 文件:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
 
import org.apache.poi.ss.usermodel.Cell;
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.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 
public class ExcelUtils {
 
    public static void readExcel(String fileName) throws IOException {
        // 创建文件输入流
        FileInputStream fileInputStream = new FileInputStream(new File(fileName));
 
        // 创建工作簿对象
        Workbook workbook = WorkbookFactory.create(fileInputStream);
 
        // 获取第一个工作表
        Sheet sheet = workbook.getSheetAt(0);
 
        // 遍历工作表中的所有行和单元格
        for (Row row : sheet) {
            for (Cell cell : row) {
                // 根据单元格的类型读取数据
                switch (cell.getCellType()) {
                    case STRING:
                        System.out.print(cell.getStringCellValue() + "\t");
                        break;
                    case NUMERIC:
                        System.out.print(cell.getNumericCellValue() + "\t");
                        break;
                    case BOOLEAN:
                        System.out.print(cell.getBooleanCellValue() + "\t");
                        break;
                    case FORMULA:
                        System.out.print(cell.getCellFormula() + "\t");
                        break;
                    case BLANK:
                        System.out.print("\t");
                        break;
                    default:
                        System.out.print("\t");
                }
            }
            System.out.println();
        }
 
        // 关闭文件输入流
        fileInputStream.close();
    }
 
    public static void writeExcel(String fileName) throws IOException {
        // 创建工作簿对象
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");
 
        // 创建行和单元格
        Row row = sheet.createRow(0);
        Cell cell = row.createCell(0);
        cell.setCellValue("Hello, World!");
 
        // 设置单元格样式
        CellStyle style = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);
        cell.setCellStyle(style);
 
        // 导出 Excel 文件
        FileOutputStream fileOut = new FileOutputStream(fileName);
        workbook.write(fileOut);
        fileOut.close();
    }
}
使用该类,我们可以方便地读取和导出 Excel 文件,如下所示:

public static void main(String[] args) throws IOException {
    String fileName = "path/to/excel/file.xlsx";
 
    // 读取 Excel 文件
    ExcelUtils.readExcel(fileName);
 
    // 导出 Excel 文件
    ExcelUtils.writeExcel(fileName);
}

6、结论

本文介绍了如何使用 Java 程序灵活读取和导出 Excel 文件。我们首先介绍了 Apache POI 库,它是 Java 操作 Office 文档的一个强大的工具。然后,我们演示了如何使用 POI 库读取 Excel 文件,并解释了如何根据单元如何设置单元格样式。最后,我们提供了一个完整的示例代码,演示了如何使用 ExcelUtils 类来读取和导出 Excel 文件。

 

Java 程序读取和导出 Excel 文件是一项非常实用的技能,尤其是在需要处理大量数据的项目中。使用 Apache POI 库,我们可以方便地读取和写入 Excel 文件,这可以大大提高我们的工作效率。

 

在实际应用中,我们需要根据具体的需求来选择读取和写入 Excel 文件的方法,以达到最好的效果。

本文出自:https://blog.csdn.net/bairo007/article/details/131818662

JAVA 泛型、序列化和复制

泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。比如我们要写一个排序方法,能够对整型数组、字符串数组甚至其他任何类型的数组进行排序,我们就可以使用 Java 泛型。

 

1 泛型方法(<E>)

你可以写一个泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

// 泛型方法 printArray
public static < E > void printArray( E[] inputArray )
{
for ( E element : inputArray ){
System.out.printf( "%s ", element );
}
}
  1. <? extends T>表示该通配符所代表的类型是 T 类型的子类。
  2. <? super T>表示该通配符所代表的类型是 T 类型的父类。

 

2 泛型类<T>

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}

3 类型通配符?

类 型 通 配 符 一 般 是 使 用 ? 代 替 具 体 的 类 型 参 数 。 例 如 List<?> 在 逻 辑 上 是

List<String>,List<Integer> 等所有 List<具体类型实参>的父类。

 

4 类型擦除

Java 中的泛型基本上都是在编译器这个层次来实现的。在生成的 Java 字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉。这个

过程就称为类型擦除。如在代码中定义的 List<Object>和 List<String>等类型,在编译之后

都会变成 List。JVM 看到的只是 List,而由泛型附加的类型信息对 JVM 来说是不可见的。

类型擦除的基本过程也比较简单,首先是找到用来替换类型参数的具体类。这个具体类一般

是 Object。如果指定了类型参数的上界的话,则使用这个上界。把代码中的类型参数都替换

成具体的类。

 

5 JAVA 序列化( 创建可复用的 Java 对象)

保存 ( 持久化 ) 对象 及其状态到内存或者磁盘

Java 平台允许我们在内存中创建可复用的 Java 对象,但一般情况下,只有当 JVM 处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比 JVM 的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java 对象序列化就能够帮助我们实现该功能。

序列化对象以字节数组保持 – 静态成员不保存

使用 Java 对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对

象序列化不会关注类中的静态变量。

序列化用户远程对象传输

除了在持久化对象时会用到对象序列化之外,当使用 RMI(远程方法调用),或在网络中传递对象时,都会用到对象序列化。Java序列化API为处理对象序列化提供了一个标准机制,该API简单易用。

Serializable 实现序列化

在 Java 中,只要一个类实现了 java.io.Serializable 接口,那么它就可以被序列化。

ObjectOutputStream 和 ObjectInputStream 对对象进行序列化及反序列化

通过 ObjectOutputStream 和 ObjectInputStream 对对象进行序列化及反序列化。

writeObject 和 readObject 自定义序列化策略

在类中增加 writeObject 和 readObject 方法可以实现自定义序列化策略。

序列化 ID

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个

类的序列化 ID 是否一致(就是 private static final long serialVersionUID)

 

序列化并不保存静态变量

序列化子父类说明

要想将父类对象也序列化,就需要让父类也实现 Serializable 接口。

Transient 关键字 阻止该变量被序列化到文件中

 

在变量声明前加上 Transient 关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

服务器端给客户端发送序列化对象数据,对象中有一些数据是敏感的,比如密码字符串等,希望对该密码字段在序列化时,进行加密,而客户端如果拥有解密的密钥,只有在客户端进行反序列化时,才可以对密码进行读取,这样可以一定程度保证序列化对象的数据安全。

6 JAVA 复制

将一个对象的引用复制给另外一个对象,一共有三种方式。第一种方式是直接赋值,第二种方式是浅拷贝,第三种是深拷贝。所以大家知道了哈,这三种概念实际上都是为了拷贝对象。

 

6.1 直接赋值复制

直接赋值。在 Java 中,A a1 = a2,我们需要理解的是这实际上复制的是引用,也就是说 a1 和 a2 指向的是同一个对象。因此,当 a1 变化的时候,a2 里面的成员变量也会跟着变化。

 

6.2 浅复制(复制引用但不复制引用的对象)

创建一个新对象,然后将当前对象的非静态字段复制到该新对象,如果字段是值类型的,那么对该字段执行复制;如果该字段是引用类型的话,则复制引用但不复制引用的对象。因此,原始对象及其副本引用同一个对象。

class Resume implements Cloneable{
public Object clone() {
try {
return (Resume)super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}

6.3 深复制(复制对象和其应用对象)

深拷贝不仅复制对象本身,而且复制对象包含的引用指向的所有对象。

 

class Student implements Cloneable {

String name;

int age;

Professor p;

Student(String name, int age, Professor p) {

this.name = name;

this.age = age;

this.p = p;

}

public Object clone() {

Student o = null;

try {

o = (Student) super.clone();

} catch (CloneNotSupportedException e) {

System.out.println(e.toString());

}

o.p = (Professor) p.clone();

return o;

}

}

 

6.4 序列化(深 clone 一中实现)

在 Java 语言里深复制一个对象,常常可以先使对象实现 Serializable 接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里,再从流里读出来,便可以重建象。

本文出自:https://blog.csdn.net/Lj_chuxuezhe/article/details/133469762