日常开发中,报表导出、数据批量规整、模板修改等场景,经常需要动态对 Excel 表格插入、删除行和列。本文将介绍如何使用 Java 操作 Excel 文件的行和列,包括对.xls、.xlsx格式表格的行、列新增与删除,附带完整可运行示例。
安装依赖
本文示例使用的是 Spire.XLS for Java,这是一个专门处理Excel文件的Java库。你可以在pom.xml文件从添加以下代码从Maven安装该库:
Maven依赖
xml
<repositories>
<repository>
<id>com.e-iceblue</id>
<url>https://repo.e-iceblue.cn/repository/maven-public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.xls</artifactId>
<version>14.12.0</version>
</dependency>
</dependencies>
一、插入行和列
最基础的操作就是插入行和列了。比如要在第2行前面插入一个新行:
java
import com.spire.xls.*;
public class InsertRowsColumns {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
// 在第2行位置插入一行
worksheet.insertRow(2);
// 在第2列位置插入一列
worksheet.insertColumn(2);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
批量插入也很简单,第二个参数指定插入的数量:
scss
// 从第5行开始,连续插入2行
worksheet.insertRow(5, 2);
// 从第5列开始,连续插入2列
worksheet.insertColumn(5, 2);
实际场景:我经常在生成报表时,根据数据量动态插入行。比如有10条记录,就在表头后面插入10行。
二、删除行和列
删除操作和插入类似,但要注意:删除后后面的行/列会自动前移。
java
import com.spire.xls.*;
public class DeleteRowsColumns {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
// 从第5行开始,删除4行(删除第5、6、7、8行)
worksheet.deleteRow(5, 4);
// 从第2列开始,删除2列(删除第2、3列)
worksheet.deleteColumn(2, 2);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
踩过的坑 :如果循环删除多行,记得从后往前删,否则索引会乱。
三、删除空白行和列
这个功能特别实用!经常遇到导出的Excel里有很多空白行,手动删太麻烦。
scss
import com.spire.xls.*;
public class DeleteBlankRows {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("messy_data.xlsx");
Worksheet sheet = workbook.getWorksheets().get(0);
// 删除空白行(从后往前遍历)
for (int i = sheet.getRows().length - 1; i >= 0; i--) {
if (sheet.getRows()[i].isBlank()) {
sheet.deleteRow(i + 1); // 注意:行号从1开始
}
}
// 删除空白列(从后往前遍历)
for (int j = sheet.getColumns().length - 1; j >= 0; j--) {
if (sheet.getColumns()[j].isBlank()) {
sheet.deleteColumn(j + 1); // 注意:列号从1开始
}
}
workbook.saveToFile("cleaned.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
为什么要从后往前删? 因为删除一行后,后面的行号会变化。如果从前往后删,可能会跳过某些行或者删错位置。
应用场景:清理从数据库导出的Excel、去除模板中的占位行等。
四、复制行和列
有时候需要在同一个Sheet内复制行,或者跨Sheet复制数据。
同一Sheet内复制
java
import com.spire.xls.*;
public class CopyRows {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet sheet = workbook.getWorksheets().get(0);
// 把第1行复制到第3行
// 参数:源行、目标行、是否复制值、是否复制格式、是否复制公式
sheet.copy(sheet.getRows()[0], sheet.getRows()[2], true, true, true);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2010);
workbook.dispose();
}
}
跨Sheet复制
ini
Worksheet sheet1 = workbook.getWorksheets().get(0);
Worksheet sheet2 = workbook.getWorksheets().get(1);
// 把Sheet1的第1行复制到Sheet2的第2行
sheet1.copy(sheet1.getRows()[0], sheet2.getRows()[1], true, true, true);
三个布尔参数说明:
- 第一个:是否复制单元格的值
- 第二个:是否复制格式(字体、颜色等)
- 第三个:是否复制公式
实际用途:我经常用它来复制表头到多个Sheet,或者根据模板行批量生成数据行。
五、隐藏和显示行列
有些敏感数据不想直接显示,可以隐藏起来:
java
import com.spire.xls.*;
public class HideRowsColumns {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
// 隐藏第2列
worksheet.hideColumn(2);
// 隐藏第4行
worksheet.hideRow(4);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
取消隐藏:
scss
// 显示第2列
worksheet.showColumn(2);
// 显示第4行
worksheet.showRow(4);
使用场景:财务报表中隐藏中间计算过程、保护敏感信息等。
六、设置行高和列宽
默认的行列尺寸可能不合适,需要自定义:
java
import com.spire.xls.*;
public class SetHeightWidth {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
// 设置第4列宽度为30
worksheet.setColumnWidth(4, 30);
// 设置第4行高度为30
worksheet.setRowHeight(4, 30);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
批量设置默认值:
scss
// 设置所有行的默认高度
worksheet.setDefaultRowHeight(20);
// 设置所有列的默认宽度
worksheet.setDefaultColumnWidth(15);
经验之谈:中文内容通常需要更宽的列,英文可以窄一些。我一般会根据内容类型预设不同的列宽。
七、自动调整列宽
如果不确定列宽设多少合适,可以让Excel自动调整:
java
import com.spire.xls.*;
public class AutoFitColumns {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet worksheet = workbook.getWorksheets().get(0);
// 自动调整指定区域的列宽
worksheet.getAllocatedRange().autoFitColumns();
// 也可以只调整某几列
// worksheet.getCellRange("A1:C10").autoFitColumns();
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
注意:自动调整会遍历所有单元格,数据量大时会比较慢。如果性能重要,建议手动设置固定宽度。
八、分组行列(大纲功能)
Excel的大纲功能可以把相关行/列折叠起来,适合层级数据:
java
import com.spire.xls.*;
public class GroupRowsColumns {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet sheet = workbook.getWorksheets().get(0);
// 对第1到5行进行分组(可以折叠)
// 第三个参数:是否在下方显示汇总行
sheet.groupByRows(1, 5, false);
// 对第1到3列进行分组
sheet.groupByColumns(1, 3, false);
workbook.saveToFile("result.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
实际场景:财务报表按月分组、项目计划按阶段分组等。用户可以选择展开或折叠查看不同粒度的数据。
九、根据条件删除行
有时候需要根据内容筛选并删除某些行,比如删除包含特定关键词的行:
ini
import com.spire.xls.*;
public class RemoveRowByKeyword {
public static void main(String[] args) {
Workbook workbook = new Workbook();
workbook.loadFromFile("data.xlsx");
Worksheet sheet = workbook.getWorksheets().get(0);
String keyword = "测试";
// 从后往前遍历,删除包含关键词的行
for (int i = sheet.getRows().length - 1; i >= 0; i--) {
boolean shouldDelete = false;
// 检查该行所有单元格
for (Object cell : sheet.getRows()[i]) {
if (cell != null && cell.toString().contains(keyword)) {
shouldDelete = true;
break;
}
}
if (shouldDelete) {
sheet.deleteRow(i + 1);
}
}
workbook.saveToFile("filtered.xlsx", ExcelVersion.Version2013);
workbook.dispose();
}
}
应用场景:清理测试数据、过滤无效记录、删除标记为废弃的行等。
十、综合实战:动态生成报表
最后分享一个完整的例子:根据数据动态生成带格式的报表。
scss
import com.spire.xls.*;
import java.util.List;
import java.util.ArrayList;
public class DynamicReport {
// 模拟数据类
static class Product {
String name;
double price;
int quantity;
Product(String name, double price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
}
public static void main(String[] args) {
Workbook workbook = new Workbook();
Worksheet sheet = workbook.getWorksheets().get(0);
// 准备数据
List<Product> products = new ArrayList<>();
products.add(new Product("产品A", 99.9, 100));
products.add(new Product("产品B", 199.9, 50));
products.add(new Product("产品C", 299.9, 30));
// 1. 写入表头
String[] headers = {"产品名称", "单价", "数量", "总价"};
for (int i = 0; i < headers.length; i++) {
sheet.getCellRange(1, i + 1).setValue(headers[i]);
}
// 格式化表头
sheet.getCellRange(1, 1, 1, headers.length).getStyle().getFont().isBold(true);
sheet.getCellRange(1, 1, 1, headers.length).getStyle()
.setKnownColor(ExcelColors.LightBlue);
// 2. 动态插入数据行
for (int i = 0; i < products.size(); i++) {
int row = i + 2; // 从第2行开始(第1行是表头)
Product p = products.get(i);
sheet.getCellRange(row, 1).setValue(p.name);
sheet.getCellRange(row, 2).setNumberValue(p.price);
sheet.getCellRange(row, 3).setNumberValue(p.quantity);
// 总价 = 单价 * 数量(使用公式)
sheet.getCellRange(row, 4).setFormula("=B" + row + "*C" + row);
sheet.getCellRange(row, 4).getStyle().setNumberFormat("¥#,##0.00");
}
// 3. 添加汇总行
int summaryRow = products.size() + 2;
sheet.getCellRange(summaryRow, 1).setValue("合计");
sheet.getCellRange(summaryRow, 1).getStyle().getFont().isBold(true);
// 汇总公式
sheet.getCellRange(summaryRow, 3).setFormula("=SUM(C2:C" + (summaryRow - 1) + ")");
sheet.getCellRange(summaryRow, 4).setFormula("=SUM(D2:D" + (summaryRow - 1) + ")");
sheet.getCellRange(summaryRow, 4).getStyle().setNumberFormat("¥#,##0.00");
// 4. 设置列宽
sheet.setColumnWidth(1, 20); // 产品名称
sheet.setColumnWidth(2, 15); // 单价
sheet.setColumnWidth(3, 15); // 数量
sheet.setColumnWidth(4, 20); // 总价
// 5. 自动调整(可选)
// sheet.getAllocatedRange().autoFitColumns();
// 6. 添加边框
sheet.getCellRange(1, 1, summaryRow, 4).getBorders()
.setLineStyle(LineStyleType.Thin);
workbook.saveToFile("product_report.xlsx", ExcelVersion.Version2013);
workbook.dispose();
System.out.println("报表生成完成!");
}
}
这个例子展示了:
- 动态插入数据行(根据数据量)
- 使用公式自动计算
- 设置格式(加粗、背景色、数字格式)
- 调整列宽
- 添加边框
小结
总结一下几个关键点:
- 插入行列用 insertRow() 和 insertColumn(),支持批量插入
- 删除行列用 deleteRow() 和 deleteColumn(),循环删除要从后往前
- 删除空白用 isBlank() 判断,清理脏数据很实用
- 复制行列用 copy() 方法,可以控制是否复制值、格式、公式
- 隐藏显示用 hideRow/Column() 和 showRow/Column()
- 设置尺寸用 setRowHeight() 和 setColumnWidth()
- 自动调整用 autoFitColumns(),但大数据量时注意性能
- 分组折叠用 groupByRows/Columns(),适合层级数据
实际使用中,最重要的是理解业务需求。不是所有场景都需要复杂的操作,有时候简单的插入和删除就能解决问题。