2023年Apache POI完全教程:Java操作Excel、Word和PowerPoint的终极指南

这是文章《Apache POI 教程》的第1部分(共4部分)。

欢迎来到Apache POI教程。有时候我们需要从Microsoft Excel文件中读取数据,或者需要生成Excel格式的报表,主要用于商业或金融目的。Java本身不提供与Excel文件的工作支持,所以我们需要寻找开源API来完成这个任务。当我开始寻找Java处理Excel的API时,大部分人推荐JExcel或Apache POI。经过进一步的研究,我发现Apache POI是首选的主要原因。还有一些高级特性相关的其他原因,但我们不需要去深入详细讨论。

  • Apache基金会的支持。
  • JExcel不支持xlsx格式,而POI同时支持xls和xlsx格式。
  • Apache POI提供基于流的处理,适合大文件处理且需要较少的内存。

Apache POI 是一个用于读写 Microsoft Office 格式文件的 Java 库。Apache POI在处理Microsoft Excel文档方面提供了出色的支持。Apache POI能够处理电子表格的XLS和XLSX格式。有关Apache POI API的一些重要要点是:

  1. Apache POI包含对Excel ’97(-2007)文件格式(即XLS)的HSSF实现。
  2. 对于Excel 2007 OOXML(.xlsx)文件格式,应使用Apache POI XSSF实现。
  3. Apache POI HSSF和XSSF API提供了读取、写入或修改电子表格的机制。
  4. Apache POI还提供了SXSSF API,它是XSSF的扩展,用于处理非常大的Excel表格。
  5. SXSSF API需要较少的内存,在处理非常大的电子表格且堆内存有限时特别适用。
  6. 有两种模型可供选择 – 事件模型和用户模型。事件模型需要较少的内存,因为Excel文件以标记形式被读取并需要进行处理。用户模型更加面向对象且易于使用,我们将在示例中使用它。
  7. Apache POI对额外的Excel功能提供了出色的支持,例如使用公式、通过填充颜色和边框、字体、页眉和页脚、数据验证、图片、超链接等创建单元格样式。

Apache POI Maven 依赖项

如果你在使用Maven,添加以下的Apache POI依赖项。

<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi</artifactId>
	<version>3.10-FINAL</version>
</dependency>
<dependency>
	<groupId>org.apache.poi</groupId>
	<artifactId>poi-ooxml</artifactId>
	<version>3.10-FINAL</version>
</dependency>

目前的Apache POI版本是3.10-FINAL。如果您使用独立的Java应用程序,请包含下方图片中的Jars。

Apache POI 示例 – 读取 Excel 文件

这是文章《Apache POI 教程》的第2部分(共4部分)。

内容片段:假设我们有一个名为”Sample.xlsx”的Excel文件,其中包含两个工作表,数据如下图所示。我们想要读取这个Excel文件,并创建一个国家列表。尽管在解析过程中Sheet1有一些额外的数据,但我们会忽略它。我们的国家Java Bean代码如下:Country.java

package com.Olivia.excel.read;

public class Country {

	private String name;
	private String shortCode;
	
	public Country(String n, String c){
		this.name=n;
		this.shortCode=c;
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getShortCode() {
		return shortCode;
	}
	public void setShortCode(String shortCode) {
		this.shortCode = shortCode;
	}
	
	@Override
	public String toString(){
		return name + "::" + shortCode;
	}
	
}

以下是一个使用Apache POI库的示例程序,可以将Excel文件读取为国家列表。ReadExcelFileToList.java:

package com.Olivia.excel.read;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ReadExcelFileToList {

	public static List<Country> readExcelData(String fileName) {
		List<Country> countriesList = new ArrayList<Country>();
		
		try {
			//从xlsx/xls文件创建输入流
			FileInputStream fis = new FileInputStream(fileName);
			
			//为xlsx/xls文件输入流创建Workbook实例
			Workbook workbook = null;
			if(fileName.toLowerCase().endsWith("xlsx")){
				workbook = new XSSFWorkbook(fis);
			}else if(fileName.toLowerCase().endsWith("xls")){
				workbook = new HSSFWorkbook(fis);
			}
			
			//获取xlsx文件中的工作表数量
			int numberOfSheets = workbook.getNumberOfSheets();
			
			//遍历每个工作表
			for(int i=0; i < numberOfSheets; i++){
				
				//从工作簿中获取第n个工作表
				Sheet sheet = workbook.getSheetAt(i);
				
				//每个工作表都有行,遍历它们
				Iterator<Row> rowIterator = sheet.iterator();
				while (rowIterator.hasNext()) 
		        {
					String name = "";
					String shortCode = "";
					
					//获取行对象
					Row row = rowIterator.next();
					
					//每行都有列,获取列迭代器并遍历它们
					Iterator<Cell> cellIterator = row.cellIterator();
		             
		            while (cellIterator.hasNext()) 
		            {
		            	//获取单元格对象
		            	Cell cell = cellIterator.next();
		            	
		            	//检查单元格类型并相应处理
		            	switch(cell.getCellType()){
		            	case Cell.CELL_TYPE_STRING:
						if(shortCode.equalsIgnoreCase("")){
							shortCode = cell.getStringCellValue().trim();
						}else if(name.equalsIgnoreCase("")){
							//第二列
							name = cell.getStringCellValue().trim();
						}else{
							//随机数据,忽略它
							System.out.println("随机数据::"+cell.getStringCellValue());
						}
						break;
		            	case Cell.CELL_TYPE_NUMERIC:
						System.out.println("随机数据::"+cell.getNumericCellValue());
		            	}
		            } //单元格迭代器结束
		            Country c = new Country(name, shortCode);
		            countriesList.add(c);
		        } //行迭代器结束
				
				
			} //工作表for循环结束
			
			//关闭文件输入流
			fis.close();
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return countriesList;
	}

	public static void main(String args[]){
		List<Country> list = readExcelData("Sample.xlsx");
		System.out.println("国家列表\n"+list);
	}

}

这个程序非常容易理解,包括以下步骤:

  1. 基于文件类型创建Workbook实例。对于xlsx格式,使用XSSFWorkbook,对于xls格式,使用HSSFWorkbook。注意我们可以使用工厂模式创建一个包装器类,根据文件名来获取Workbook实例。
  2. 使用workbook的getNumberOfSheets()方法获取表格的数量,然后使用for循环解析每个表格。使用getSheetAt(int i)方法获取Sheet实例。
  3. 获取Row迭代器,然后获取Cell迭代器以获取Cell对象。Apache POI在这里使用了迭代器模式。
  4. 使用switch-case语句读取Cell的类型并进行相应的处理。

现在,当我们运行上述 Apache POI 示例程序时,它会在控制台上生成以下输出:

随机数据::1.0
随机数据::2.0
随机数据::3.0
随机数据::4.0
国家列表
[India::IND, Afghanistan::AFG, United States of America::USA, Anguilla::AIA, 
Denmark::DNK, Dominican Republic::DOM, Algeria::DZA, Ecuador::ECU]

Apache POI 示例 – 写入 Excel 文件

这是文章《Apache POI 教程》的第3部分(共4部分)。

内容片段:使用Apache POI编写Excel文件与读取类似,只是在这里我们首先创建工作簿。然后设置工作表、行和单元格的值,并使用FileOutputStream将其写入文件。让我们编写一个简单的Apache POI示例,我们将使用上述方法中的国家列表将其保存到另一个文件中的单个工作表中。WriteListToExcelFile.java

package com.Olivia.excel.read;

import java.io.FileOutputStream;
import java.util.Iterator;
import java.util.List;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
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.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class WriteListToExcelFile {

	public static void writeCountryListToFile(String fileName, List<Country> countryList) throws Exception{
		Workbook workbook = null;
		
		if(fileName.endsWith("xlsx")){
			workbook = new XSSFWorkbook();
		}else if(fileName.endsWith("xls")){
			workbook = new HSSFWorkbook();
		}else{
			throw new Exception("invalid file name, should be xls or xlsx");
		}
		
		Sheet sheet = workbook.createSheet("Countries");
		
		Iterator<Country> iterator = countryList.iterator();
		
		int rowIndex = 0;
		while(iterator.hasNext()){
			Country country = iterator.next();
			Row row = sheet.createRow(rowIndex++);
			Cell cell0 = row.createCell(0);
			cell0.setCellValue(country.getName());
			Cell cell1 = row.createCell(1);
			cell1.setCellValue(country.getShortCode());
		}
		
		//lets write the excel data to file now
		FileOutputStream fos = new FileOutputStream(fileName);
		workbook.write(fos);
		fos.close();
		System.out.println(fileName + " written successfully");
	}
	
	public static void main(String args[]) throws Exception{
		List<Country> list = ReadExcelFileToList.readExcelData("Sample.xlsx");
		WriteListToExcelFile.writeCountryListToFile("Countries.xls", list);
	}
}

当我们执行上述Apache POI示例程序时,生成的Excel文件看起来如下所示的图片。

Apache POI示例 – 读取Excel公式

有时候我们需要处理包含公式的复杂Excel文件,让我们来看一个使用简单Apache POI的例子,来读取带有其值的单元格的公式。ReadExcelFormula.java

package com.Olivia.excel.read;

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;

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.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class ReadExcelFormula {

	public static void readExcelFormula(String fileName) throws IOException{
		
		FileInputStream fis = new FileInputStream(fileName);
		
		//assuming xlsx file
		Workbook workbook = new XSSFWorkbook(fis);
		Sheet sheet = workbook.getSheetAt(0);
		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 Cell.CELL_TYPE_NUMERIC:
            		System.out.println(cell.getNumericCellValue());
            		break;
            	case Cell.CELL_TYPE_FORMULA:
            		System.out.println("Cell Formula="+cell.getCellFormula());
            		System.out.println("Cell Formula Result Type="+cell.getCachedFormulaResultType());
            		if(cell.getCachedFormulaResultType() == Cell.CELL_TYPE_NUMERIC){
            			System.out.println("Formula Value="+cell.getNumericCellValue());
            		}
            	}
            }
        }
	}
	
	public static void main(String args[]) throws IOException {
		readExcelFormula("FormulaMultiply.xlsx");
	}
}

当我们执行以上Apache POI示例程序时,我们会得到以下输出结果。

1.0
2.0
3.0
4.0
单元格公式=A1*A2*A3*A4
单元格公式结果类型=0
公式值=24.0

Apache POI示例 – Excel写入公式

这是文章《Apache POI 教程》的第4部分(共4部分)。

有时候,我们需要进行一些计算,然后将结果写入单元格。我们可以使用Excel公式来进行计算,这样做的好处是,如果计算中涉及的单元格值发生变化,结果会自动更新,从而确保计算的准确性和实时性。下面让我们通过一个简单示例,学习如何使用Apache POI API创建带有公式的Excel文件,该示例类命名为WriteExcelWithFormula.java。

package com.Olivia.excel.read;

import java.io.FileOutputStream;
import java.io.IOException;

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.xssf.usermodel.XSSFWorkbook;

public class WriteExcelWithFormula {

	public static void writeExcelWithFormula(String fileName) throws IOException{
		// 创建一个新的工作簿
		Workbook workbook = new XSSFWorkbook();
		// 创建名为"Numbers"的工作表
		Sheet sheet = workbook.createSheet("Numbers");
		// 创建第一行
		Row row = sheet.createRow(0);
		// 在单元格中设置数值
		row.createCell(0).setCellValue(10);
		row.createCell(1).setCellValue(20);
		row.createCell(2).setCellValue(30);
		// 设置公式单元格
		row.createCell(3).setCellFormula("A1*B1*C1");
		
		// 将工作簿写入文件
		FileOutputStream fos = new FileOutputStream(fileName);
		workbook.write(fos);
		fos.close();
		System.out.println(fileName + " 文件写入成功");
	}
	
	public static void main(String[] args) throws IOException {
		writeExcelWithFormula("Formulas.xlsx");
	}
}

上述Apache POI API示例程序生成的Excel文件效果如下图所示。至此,我们已经完成了关于使用Apache POI处理Excel文件的完整教程。若想了解更多功能,建议查阅Apache POI类中的各种方法。参考资料:Apache POI开发者指南。

bannerAds