Java 操作 XLSX 文件:从入门到实践
简介
在日常的开发工作中,处理 Excel 文件是一项常见的任务。XLSX 是 Microsoft Excel 2007 及更高版本使用的文件格式,基于 XML 标准。Java 作为一种广泛应用的编程语言,提供了多种方式来操作 XLSX 文件。本文将深入探讨 Java 操作 XLSX 的基础概念、使用方法、常见实践以及最佳实践,帮助读者快速掌握这一技能并在项目中高效应用。
目录
- 基础概念
- XLSX 文件结构
- Java 操作 XLSX 的相关库
- 使用方法
- 读取 XLSX 文件
- 写入 XLSX 文件
- 常见实践
- 数据处理与转换
- 样式设置
- 最佳实践
- 性能优化
- 错误处理与异常处理
- 小结
- 参考资料
基础概念
XLSX 文件结构
XLSX 文件本质上是一个压缩包,包含多个 XML 文件和相关资源。其中,主要的 XML 文件包括:
- workbook.xml
:包含工作簿的全局信息,如工作表列表、共享字符串表等。
- worksheet*.xml
:每个工作表对应一个 XML 文件,存储工作表的实际数据、单元格格式等信息。
- styles.xml
:存储所有的样式信息,如字体、颜色、对齐方式等。
Java 操作 XLSX 的相关库
- Apache POI:是一个广泛使用的 Java 库,提供了丰富的 API 来操作各种 Office 格式文件,包括 XLSX。它支持读取、写入、修改 XLSX 文件的内容和样式。
- EasyExcel:是一个基于 Apache POI 封装的轻量级库,专注于简化 Excel 文件的读写操作。它在性能和易用性方面有不错的表现。
使用方法
读取 XLSX 文件
以 Apache POI 为例,读取 XLSX 文件的代码示例如下:
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class XlsxReader {
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) {
String cellValue = getCellValue(cell);
System.out.print(cellValue + "\t");
}
System.out.println();
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue().toString();
} else {
return String.valueOf(cell.getNumericCellValue());
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
}
写入 XLSX 文件
以下是使用 Apache POI 写入 XLSX 文件的示例:
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class XlsxWriter {
public static void main(String[] args) {
String filePath = "path/to/output/file.xlsx";
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fos = new FileOutputStream(new File(filePath))) {
Sheet sheet = workbook.createSheet("Sheet1");
for (int i = 0; i < 5; i++) {
Row row = sheet.createRow(i);
for (int j = 0; j < 3; j++) {
Cell cell = row.createCell(j);
cell.setCellValue("Cell (" + i + ", " + j + ")");
}
}
workbook.write(fos);
} catch (IOException e) {
e.printStackTrace();
}
}
}
常见实践
数据处理与转换
在读取 XLSX 文件后,通常需要对数据进行处理和转换。例如,将读取到的数据转换为 Java 对象,以便进行后续的业务逻辑处理。
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// Getters and Setters
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class DataProcessing {
public static void main(String[] args) {
String filePath = "path/to/person_data.xlsx";
List<Person> personList = new ArrayList<>();
try (FileInputStream fis = new FileInputStream(new File(filePath));
Workbook workbook = new XSSFWorkbook(fis)) {
Sheet sheet = workbook.getSheetAt(0);
for (Row row : sheet) {
if (row.getRowNum() == 0) {
// Skip header row
continue;
}
Cell nameCell = row.getCell(0);
Cell ageCell = row.getCell(1);
String name = getCellValue(nameCell);
int age = (int) Double.parseDouble(getCellValue(ageCell));
Person person = new Person(name, age);
personList.add(person);
}
for (Person person : personList) {
System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
}
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getCellValue(Cell cell) {
if (cell == null) {
return "";
}
switch (cell.getCellType()) {
case STRING:
return cell.getStringCellValue();
case NUMERIC:
if (org.apache.poi.ss.usermodel.DateUtil.isCellDateFormatted(cell)) {
return cell.getDateCellValue().toString();
} else {
return String.valueOf(cell.getNumericCellValue());
}
case BOOLEAN:
return String.valueOf(cell.getBooleanCellValue());
case FORMULA:
return cell.getCellFormula();
default:
return "";
}
}
}
样式设置
可以使用 Apache POI 对 XLSX 文件的单元格进行样式设置,如字体、颜色、对齐方式等。
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
public class StyleSetting {
public static void main(String[] args) {
String filePath = "path/to/styled_file.xlsx";
try (Workbook workbook = new XSSFWorkbook();
FileOutputStream fos = new FileOutputStream(new File(filePath))) {
Sheet sheet = workbook.createSheet("Styled Sheet");
Row row = sheet.createRow(0);
Cell cell = row.createCell(0);
cell.setCellValue("Styled Cell");
CellStyle style = workbook.createCellStyle();
Font font = workbook.createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short) 14);
font.setColor(Font.COLOR_RED);
style.setFont(font);
style.setAlignment(CellStyle.ALIGN_CENTER);
cell.setCellStyle(style);
workbook.write(fos);
} catch (IOException e) {
e.printStackTrace();
}
}
}
最佳实践
性能优化
- 使用流式处理:对于大型 XLSX 文件,使用 Apache POI 的 SAX 模式(事件驱动模式)进行读取,可以避免将整个文件加载到内存中,从而提高性能。例如:
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import java.io.IOException;
import java.io.InputStream;
public class StreamingXlsxReader {
public static void main(String[] args) throws IOException, SAXException {
String filePath = "path/to/large_file.xlsx";
OPCPackage pkg = OPCPackage.open(new File(filePath));
XSSFReader xssfReader = new XSSFReader(pkg);
SharedStringsTable sst = xssfReader.getSharedStringsTable();
XMLReader parser = XMLReaderFactory.createXMLReader();
ContentHandler handler = new ContentHandler(sst);
parser.setContentHandler(handler);
InputStream sheet1 = xssfReader.getSheet("rId1");
InputSource sheetSource = new InputSource(sheet1);
parser.parse(sheetSource);
}
private static class ContentHandler extends DefaultHandler {
private SharedStringsTable sst;
private StringBuilder cellValue = new StringBuilder();
private boolean isCellValue = false;
public ContentHandler(SharedStringsTable sst) {
this.sst = sst;
}
@Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if ("c".equals(qName)) {
isCellValue = true;
cellValue.setLength(0);
}
}
@Override
public void characters(char[] ch, int start, int length) throws SAXException {
if (isCellValue) {
cellValue.append(ch, start, length);
}
}
@Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if ("c".equals(qName)) {
isCellValue = false;
String cellText = cellValue.toString();
if (cellText.startsWith("s")) {
int idx = Integer.parseInt(cellText.substring(1));
cellText = sst.getItemAt(idx).getString();
}
System.out.print(cellText + "\t");
} else if ("row".equals(qName)) {
System.out.println();
}
}
}
}
- 批量写入:在写入 XLSX 文件时,尽量减少对文件的写入操作次数。可以先将数据存储在内存中,然后一次性写入文件。
错误处理与异常处理
在操作 XLSX 文件时,要做好错误处理和异常处理。例如,在读取文件时可能会遇到文件不存在、格式错误等问题,在写入文件时可能会遇到权限不足等问题。使用 try-catch 块捕获异常,并进行适当的处理,如记录日志、向用户提示错误信息等。
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class ExceptionHandling {
public static void main(String[] args) {
String filePath = "path/to/file.xlsx";
try (FileInputStream fis = new FileInputStream(new File(filePath));
Workbook workbook = new XSSFWorkbook(fis)) {
// 正常处理逻辑
} catch (IOException e) {
System.err.println("Error reading XLSX file: " + e.getMessage());
e.printStackTrace();
}
}
}
小结
本文详细介绍了 Java 操作 XLSX 文件的相关知识,包括基础概念、使用方法、常见实践以及最佳实践。通过学习这些内容,读者可以掌握如何使用 Java 读取、写入和处理 XLSX 文件,并且能够在实际项目中优化性能、处理异常,提高开发效率和代码质量。