Java 如何插入和删除 Excel 行和列

日常开发中,报表导出、数据批量规整、模板修改等场景,经常需要动态对 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("报表生成完成!");
    }
}

这个例子展示了:

  • 动态插入数据行(根据数据量)
  • 使用公式自动计算
  • 设置格式(加粗、背景色、数字格式)
  • 调整列宽
  • 添加边框

小结

总结一下几个关键点:

  1. 插入行列用 insertRow() 和 insertColumn(),支持批量插入
  2. 删除行列用 deleteRow() 和 deleteColumn(),循环删除要从后往前
  3. 删除空白用 isBlank() 判断,清理脏数据很实用
  4. 复制行列用 copy() 方法,可以控制是否复制值、格式、公式
  5. 隐藏显示用 hideRow/Column() 和 showRow/Column()
  6. 设置尺寸用 setRowHeight() 和 setColumnWidth()
  7. 自动调整用 autoFitColumns(),但大数据量时注意性能
  8. 分组折叠用 groupByRows/Columns(),适合层级数据

实际使用中,最重要的是理解业务需求。不是所有场景都需要复杂的操作,有时候简单的插入和删除就能解决问题。

相关推荐
@SmartSi4 小时前
AgentScope Java 入门:如何使用 OpenAIChatModel 集成兼容 OpenAI 协议模型
java·agentscope
就叫_这个吧4 小时前
Java线程池应用的四种方式+线程池底层实现原理
java·开发语言
Dicky-_-zhang4 小时前
Java并发编程实战:线程池与并发工具类
java·jvm
devilnumber4 小时前
JDK6→JDK7→JDK8 重点技术更新(精简背诵版)
java
云烟成雨TD4 小时前
Spring AI Alibaba 1.x 系列【61】Graph 持久化执行
java·人工智能·spring
muqsen4 小时前
Java 分布式相关面试题总结
java·开发语言·分布式
做个文艺程序员4 小时前
第02篇:搭建 ES 集群 + Spring Boot 整合实战——从 Docker Compose 到 Java 客户端全覆盖
java·spring boot·elasticsearch
Jinkxs4 小时前
LoadBalancer- 简单限流策略:Nginx 基于连接 / 请求的限流实现
java·运维·nginx
fenglllle4 小时前
JDK8升级JDK17使用CompletableFuture在线程中classloader的变化
java·开发语言·jvm