在Java中使用Apache POI保留Excel样式合并多个工作簿

背景

在日常工作中,我们经常需要将多个Excel文件合并成一个,同时保留原有的样式和格式。Apache POI是一个流行的Java库,用于读取和写入Microsoft Office格式的文件,包括Excel。然而,仅仅使用Apache POI的基本功能进行合并操作往往会导致样式的丢失,这对于需要保留格式信息的场景来说是不够的。常见的应用场景如钉钉的打卡数据只能一个一个的表格导出,接下来的文章就恰好可以运用到这样的场景中。

本文将探讨如何在合并Excel文件时保留原表格的样式,并提供一个改进的代码示例,以便更好地处理这个问题。

问题描述

在合并多个Excel文件时,常见的挑战之一是保留每个文件中的单元格样式。这些样式可能包括字体、颜色、边框、填充等。使用Apache POI的基本方法复制单元格时,只会复制内容,而不会保留这些样式。

解决方案

要解决这个问题,我们需要使用Apache POI的更高级功能来复制单元格样式。这涉及到创建样式映射,以便在合并过程中跟踪和复制每个单元格的样式。

以下是实现这一功能的关键步骤:

创建样式映射:使用一个映射结构(如HashMap)来存储从原始工作簿的CellStyle到合并工作簿的XSSFCellStyle的映射。这可以确保我们不会为相同的样式重复创建新的XSSFCellStyle对象。

遍历工作簿和工作表:对于要合并的每个Excel文件,遍历其中的每个工作簿和工作表。

复制行和单元格:对于每个工作表中的行和单元格,创建新的行和单元格,并复制内容。

复制样式:在复制单元格时,检查样式映射是否已经包含了该单元格的样式。如果没有,从原始工作簿中克隆样式,并将其添加到映射中。然后,将新克隆的样式应用到新创建的单元格上。

写入合并后的工作簿:最后,将合并后的工作簿写入输出文件。

代码示例

下面是一个示例代码,展示了如何实现上述解决方案:

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

案例一:多个excel合成一个表格

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class ExcelMerger {
    public static void main(String[] args) {
        List<String> fileNames = new ArrayList<>();
        fileNames.add("H:\\time\\_打卡时间表1.xlsx");
        fileNames.add("H:\\time\\_打卡时间表2.xlsx");
        fileNames.add("H:\\time\\_打卡时间表3.xlsx");
        // 添加更多文件路径...

        String outputFileName = "H:\\time\\merged_excel_file.xlsx";

        try{
            InputStream inputStream;Workbook workbook;
            OutputStream outputStream = new FileOutputStream(outputFileName);
            XSSFWorkbook mergedWorkbook = new XSSFWorkbook();
            int j = 0;
            for (String fileName : fileNames) {
                inputStream = new FileInputStream(fileName);
                workbook = WorkbookFactory.create(inputStream);
                j ++;
                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {
                    Sheet sheet = workbook.getSheetAt(i);
                    try {
                        mergedWorkbook.createSheet(sheet.getSheetName() + i + j);
                    }catch (Exception e){
                        System.out.println(1);
                    }
                    copySheet(mergedWorkbook.getSheet(sheet.getSheetName() + i + j), sheet);
                }
            }

            mergedWorkbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void copySheet(Sheet newSheet, Sheet sheet) {
        int rowCount = sheet.getLastRowNum() - sheet.getFirstRowNum();
        for (int i = 0; i <= rowCount; i++) {
            Row newRow = newSheet.createRow(i);
            Row currentRow = sheet.getRow(i);
            copyRow(newRow, currentRow);
        }
    }

    private static void copyRow(Row newRow, Row currentRow) {
        if (currentRow == null) {
            return;
        }

        int cellCount = currentRow.getLastCellNum();
        for (int i = 0; i < cellCount; i++) {
            Cell currentCell = currentRow.getCell(i);
            if (currentCell == null) {
                continue;
            }
            Cell newCell = newRow.createCell(i);
            copyCell(newCell, currentCell);
        }
    }

    private static void copyCell(Cell newCell, Cell currentCell) {
        newCell.setCellType(currentCell.getCellType());
        switch (currentCell.getCellType()) {
            case STRING:
                newCell.setCellValue(currentCell.getStringCellValue());
                break;
            case BOOLEAN:
                newCell.setCellValue(currentCell.getBooleanCellValue());
                break;
            case NUMERIC:
                newCell.setCellValue(currentCell.getNumericCellValue());
                break;
            case FORMULA:
                newCell.setCellFormula(currentCell.getCellFormula());
                break;
            default:
                break;
        }
    }
}

案例二:多个表格合成一个sheet

//初始化一个XSSFWorkbook实例作为合并后的工作簿,并创建一个名为"Merged Sheet"的新sheet。
//遍历每个要合并的Excel文件,并对每个文件中的每个sheet进行迭代。
//对于每个sheet中的每一行,都创建一个新的行并复制到合并后的sheet中。
//在复制行时,同时复制每个单元格的内容,包括字符串、布尔值、数字和公式。
//最后,将合并后的工作簿写入输出文件。
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;  
  
import java.io.*;  
import java.util.ArrayList;  
import java.util.List;  
  
public class ExcelMerger {
    public static void main(String[] args) {  
        List<String> fileNames = new ArrayList<>();
        fileNames.add("H:\\time\\_打卡时间表1.xlsx");
        fileNames.add("H:\\time\\_打卡时间表2.xlsx");
        fileNames.add("H:\\time\\_打卡时间表3.xlsx");
        // 添加更多文件路径...

        String outputFileName = "H:\\time\\merged_excel_file.xlsx";
  
        try {
            InputStream inputStream; Workbook workbook;
            FileOutputStream outputStream = new FileOutputStream(outputFileName);
            XSSFWorkbook mergedWorkbook = new XSSFWorkbook();  
            Sheet mergedSheet = mergedWorkbook.createSheet("Merged Sheet");  
  
            int rowNum = 0; // 用于新sheet中的行号  
  
            for (String fileName : fileNames) {  
                inputStream = new FileInputStream(fileName);  
                workbook = WorkbookFactory.create(inputStream);  
  
                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {  
                    Sheet sheet = workbook.getSheetAt(i);  
                    for (Row row : sheet) {  
                        Row newRow = mergedSheet.createRow(rowNum++);  
                        copyRow(newRow, row);  
                    }  
                }  
            }  
  
            mergedWorkbook.write(outputStream);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
    private static void copyRow(Row newRow, Row currentRow) {  
        if (currentRow == null) {  
            return;  
        }  
  
        for (Cell cell : currentRow) {  
            Cell newCell = newRow.createCell(cell.getColumnIndex(), cell.getCellType());  
            switch (cell.getCellType()) {  
                case STRING:  
                    newCell.setCellValue(cell.getStringCellValue());  
                    break;  
                case BOOLEAN:  
                    newCell.setCellValue(cell.getBooleanCellValue());  
                    break;  
                case NUMERIC:  
                    newCell.setCellValue(cell.getNumericCellValue());  
                    break;  
                case FORMULA:  
                    newCell.setCellFormula(cell.getCellFormula());  
                    break;  
                case BLANK:  
                    // Handle blank cells as needed  
                    break;  
                default:  
                    break;  
            }  
        }  
    }  
}

案例三:多个表格合成一个sheet,并保留样式

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;  
import org.apache.poi.xssf.usermodel.XSSFWorkbook;  
  
import java.io.*;  
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class ExcelMergerWithStyles {  
    public static void main(String[] args) {  
        List<String> fileNames = new ArrayList<>();
        fileNames.add("H:\\time\\_打卡时间表1.xlsx");
        fileNames.add("H:\\time\\_打卡时间表2.xlsx");
        fileNames.add("H:\\time\\_打卡时间表3.xlsx");
        // 添加更多文件路径...

        String outputFileName = "H:\\time\\merged_excel_file.xlsx";
 
        try  {
            InputStream inputStream;
            Workbook workbook;
            FileOutputStream outputStream = new FileOutputStream(outputFileName);
            XSSFWorkbook mergedWorkbook = new XSSFWorkbook();  
            Sheet mergedSheet = mergedWorkbook.createSheet("Merged Sheet");  
  
            int rowNum = 0; // 用于新sheet中的行号  
  
            // 用于存储已创建样式的映射,以避免重复创建相同的样式  
            Map<CellStyle, XSSFCellStyle> styleMap = new HashMap<>();
  
            for (String fileName : fileNames) {  
                inputStream = new FileInputStream(fileName);  
                workbook = WorkbookFactory.create(inputStream);  
  
                for (int i = 0; i < workbook.getNumberOfSheets(); i++) {  
                    Sheet sheet = workbook.getSheetAt(i);  
                    for (Row row : sheet) {  
                        Row newRow = mergedSheet.createRow(rowNum++);  
                        copyRowWithStyles(newRow, row, mergedWorkbook, styleMap);  
                    }  
                }  
            }  
  
            mergedWorkbook.write(outputStream);  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  
  
    private static void copyRowWithStyles(Row newRow, Row currentRow, XSSFWorkbook mergedWorkbook,  
                                            Map<CellStyle, XSSFCellStyle> styleMap) {  
        if (currentRow == null) {  
            return;  
        }  
  
        for (Cell cell : currentRow) {  
            Cell newCell = newRow.createCell(cell.getColumnIndex(), cell.getCellType());  
            copyCellContent(cell, newCell);  
  
            // 复制样式  
            CellStyle cellStyle = cell.getCellStyle();  
            XSSFCellStyle newCellStyle = styleMap.get(cellStyle);  
  
            if (newCellStyle == null) {  
                newCellStyle = mergedWorkbook.createCellStyle();  
                newCellStyle.cloneStyleFrom(cellStyle);  
                styleMap.put(cellStyle, newCellStyle);  
            }  
  
            newCell.setCellStyle(newCellStyle);  
        }  
    }  
  
    private static void copyCellContent(Cell source, Cell target) {  
        switch (source.getCellType()) {  
            case STRING:  
                target.setCellValue(source.getStringCellValue());  
                break;  
            case BOOLEAN:  
                target.setCellValue(source.getBooleanCellValue());  
                break;  
            case NUMERIC:  
                target.setCellValue(source.getNumericCellValue());  
                break;  
            case FORMULA:  
                target.setCellFormula(source.getCellFormula());  
                break;  
            case BLANK:  
                // Handle blank cells as needed  
                break;  
            default:  
                break;  
        }  
    }  
}

总结

通过扩展Apache POI库的基本功能,我们可以实现在合并Excel文件时保留原表格样式的能力。这涉及到创建样式映射,遍历工作簿和工作表,复制行、单元格和样式,并最终写入合并后的工作簿。虽然这个过程可能比简单的合并更为复杂,但它提供了更大的灵活性,允许我们根据需要定制合并后的Excel文件的样式和格式。

对于需要处理大量Excel文件或具有复杂样式的场景,这种方法可能需要进行进一步的优化和错误处理。但无论如何,它提供了一个很好的起点,用于在Java中实现具有样式保留功能的Excel合并操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三省同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值