You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Apache POI生成XLS文件时部分行样式丢失问题求助

问题分析与解决方案

从你的描述和代码来看,虽然样式总数没超过XLS的4000上限,但样式丢失的问题主要是由样式创建与复用逻辑的错误、未完成的方法以及引用类型的样式被意外修改导致的,具体原因和修复方案如下:

核心问题分析

1. 未完成的createStyleObject方法

你贴出的代码里,createStyleObject方法只写了一半:

private static CellStyle createStyleObject() { Workbook workbook = spreadshe

这会导致该方法无法正确返回CellStyle对象,当样式数量达到75后,后续尝试获取样式时会拿到null,直接造成单元格样式丢失。

2. 样式复用逻辑混乱

  • 比如在case 1中,你设置完列1的样式后,错误执行了styles.put(0, style);,这会把列1的样式覆盖列0的样式,导致两列样式混乱。
  • 动态判断workbook.getNumCellStyles() <75的逻辑不合理:当样式数达到75后,新行的某些列可能还没在styles中存入对应样式,导致style为null,单元格无样式。

3. 复用样式被意外修改

在日期列(case2、5、8、9)的处理中,你每次都会给style重新设置DataFormat:

style.setDataFormat(poiFormat.getFormat(excelFormatPattern));

由于CellStyle是引用类型,修改已复用的样式对象会影响所有使用该样式的单元格,导致格式被意外覆盖,看起来像是样式丢失。

4. 过时的日期构造方法

使用new Date(rowNo %10, rowNo%12...)是过时的API,且年份从1900开始计算,可能导致日期显示异常(虽然不是样式丢失的直接原因,但需要修正)。

修复后的完整代码

我们重构样式逻辑,提前初始化所有需要的样式,避免动态创建的混乱,同时修正所有错误点:

import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.DateFormatConverter;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

public class ExcelSheet {
    static Workbook workbook;
    static Sheet spreadsheet;
    static Map<Integer, CellStyle> styles = new HashMap<>();

    public static void main(String[] args) throws IOException {
        workbook = new HSSFWorkbook();
        spreadsheet = workbook.createSheet("Employee Info");
        
        // 提前初始化所有需要的样式,避免循环中动态创建的混乱
        initAllStyles();

        System.out.println("Writing data to excel...");
        for (int i = 1; i < 500; i++) {
            Row row = spreadsheet.createRow(i);
            createCells(row, i);
        }

        for (int i = 0; i < 10; i++) {
            spreadsheet.setColumnWidth(i, 4500);
        }

        FileOutputStream out = new FileOutputStream(new File("E:\\Dan\\Writesheet.xls"));
        System.out.println("No. of cell styles : " + workbook.getNumCellStyles());
        System.out.println("No. of font styles : " + workbook.getNumberOfFonts());
        workbook.write(out);
        out.close();
    }

    // 初始化所有列需要的样式,复用相同格式的样式
    private static void initAllStyles() {
        DataFormat poiFormat = workbook.createDataFormat();
        String dateFormatPattern = DateFormatConverter.convert(Locale.US, "yyyy-MM-dd");
        short dateFormatIndex = poiFormat.getFormat(dateFormatPattern);

        // 数字通用样式
        CellStyle numStyle = workbook.createCellStyle();
        setCommonBorder(numStyle);
        numStyle.setAlignment(HorizontalAlignment.RIGHT);

        // 字符串通用样式
        CellStyle strStyle = workbook.createCellStyle();
        setCommonBorder(strStyle);
        strStyle.setAlignment(HorizontalAlignment.LEFT);

        // 日期通用样式(复用数字样式的边框,仅修改格式)
        CellStyle dateStyle = workbook.createCellStyle();
        dateStyle.cloneStyleFrom(numStyle);
        dateStyle.setDataFormat(dateFormatIndex);

        // 给每列分配对应的样式,相同格式直接复用
        styles.put(0, numStyle);    // 列0:数字
        styles.put(1, strStyle);    // 列1:字符串
        styles.put(2, dateStyle);   // 列2:日期
        styles.put(3, numStyle);    // 列3:数字(复用)
        styles.put(4, strStyle);    // 列4:字符串(复用)
        styles.put(5, dateStyle);   // 列5:日期(复用)
        styles.put(6, numStyle);    // 列6:数字(复用)
        styles.put(7, strStyle);    // 列7:字符串(复用)
        styles.put(8, dateStyle);   // 列8:日期(复用)
        styles.put(9, dateStyle);   // 列9:日期(复用)
    }

    // 设置单元格通用边框样式,避免重复代码
    private static void setCommonBorder(CellStyle style) {
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
    }

    private static void createCells(Row row, int rowNo) {
        for (int i = 0; i < 10; i++) {
            Cell cell = row.createCell(i);
            try {
                writeData(cell, i, rowNo);
            } catch (Exception e) {
                System.out.println("Exception : " + e);
            }
        }
    }

    private static void writeData(Cell cell, int i, int rowNo) throws Exception {
        CellStyle style = styles.get(i);
        if (style == null) {
            // 默认使用字符串样式
            style = styles.get(7);
        }

        switch (i) {
            case 0:
                cell.setCellValue(rowNo);
                cell.setCellType(CellType.NUMERIC);
                break;
            case 1:
                cell.setCellValue("Test Data " + rowNo);
                cell.setCellType(CellType.STRING);
                break;
            case 2:
                // 使用Calendar代替过时的Date构造方法
                Calendar cal = Calendar.getInstance();
                cal.set(1900 + (rowNo % 10), rowNo % 12, rowNo % 28, rowNo % 12, rowNo % 60, rowNo % 60);
                cell.setCellValue(cal.getTime());
                break;
            case 3:
                cell.setCellValue(rowNo + rowNo);
                cell.setCellType(CellType.NUMERIC);
                break;
            case 4:
                cell.setCellValue("Sample Text " + rowNo);
                cell.setCellType(CellType.STRING);
                break;
            case 5:
                Calendar cal5 = Calendar.getInstance();
                cal5.set(1900 + (rowNo % 18), rowNo % 12, rowNo % 28, rowNo % 12, rowNo % 60, rowNo % 60);
                cell.setCellValue(cal5.getTime());
                break;
            case 6:
                cell.setCellValue(rowNo + i);
                cell.setCellType(CellType.NUMERIC);
                break;
            case 7:
                cell.setCellValue("Exports Data " + rowNo);
                cell.setCellType(CellType.STRING);
                break;
            case 8:
                Calendar cal8 = Calendar.getInstance();
                cal8.set(1900 + (rowNo % 25), rowNo % 12, rowNo % 28, rowNo % 12, rowNo % 60, rowNo % 60);
                cell.setCellValue(cal8.getTime());
                break;
            case 9:
                cell.setCellValue(new Date());
                break;
            default:
                cell.setCellValue("Default Value " + rowNo);
                cell.setCellType(CellType.STRING);
                break;
        }
        cell.setCellStyle(style);
    }
}

POI使用CellStyle的最佳实践

  1. 提前创建所有样式:不要在循环中动态创建样式,避免逻辑混乱和样式数量失控。
  2. 复用相同样式:相同格式的单元格使用同一个CellStyle对象,减少样式总数。
  3. 避免修改已复用的样式:CellStyle是引用类型,修改一个会影响所有使用该样式的单元格;如果需要不同样式,先通过cloneStyleFrom复制再修改。
  4. 注意XLS的样式限制:虽然XLS允许最多4000个样式,但过多样式会导致文件变大、性能下降,尽量精简。

内容的提问来源于stack exchange,提问作者user1300073

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:23:49