Java Apache POI 日期插入优化:解决 Excel 数据处理死循环

在使用 Java 和 Apache POI 库处理 Excel 文件时,经常需要在现有数据集中插入日期。这可能包括填充缺失日期、生成时间序列或对时间敏感的数据进行操作。

问题

一个常见问题是在插入日期时遇到无限循环,特别是当目标是插入中间日期直到相邻日期之间存在特定间隔时。如果处理不当,这可能会导致程序无限期地运行,消耗过多的资源并最终导致崩溃。

问题代码示例javapackage Data_Recovery;

import java.io.FileInputStream;import java.io.FileOutputStream;import java.text.SimpleDateFormat;import java.util.ArrayList;import java.util.Date;import java.util.List;

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

public class EM03 { public static void main(String[] args) { try { // 读取input-2.xlsx文件 FileInputStream file = new FileInputStream('input-2.xlsx'); Workbook workbook = new XSSFWorkbook(file); Sheet sheet = workbook.getSheet('P1');

        // 检查是否存在P2工作表,如果存在则删除            if (workbook.getSheet('P2') != null) {                workbook.removeSheetAt(workbook.getSheetIndex('P2'));            }

        // 创建新的P2工作表            Sheet newSheet = workbook.createSheet('P2');

        // 复制P1工作表的单元格格式到P2工作表            copyCellStyle(sheet, newSheet);

        // 获取P1工作表第一列的时间日期数据            List<Date> dates = getColumnValues(sheet);

        // 进行日期插入操作            List<Date> newDates = insertDates(dates);

        // 将插入后的日期写入P2工作表            writeColumnValues(newSheet, newDates);

        // 保存结果到input-2.xlsx文件            FileOutputStream outFile = new FileOutputStream('input-2.xlsx');            workbook.write(outFile);            outFile.close();

        System.out.println('操作完成');        } catch (Exception e) {            e.printStackTrace();        }    }

// 复制单元格格式    private static void copyCellStyle(Sheet sourceSheet, Sheet targetSheet) {        for (int rowIndex = 0; rowIndex <= sourceSheet.getLastRowNum(); rowIndex++) {            Row sourceRow = sourceSheet.getRow(rowIndex);            Row targetRow = targetSheet.createRow(rowIndex);

        for (int columnIndex = 0; columnIndex < sourceRow.getLastCellNum(); columnIndex++) {                Cell sourceCell = sourceRow.getCell(columnIndex);                Cell targetCell = targetRow.createCell(columnIndex);

            if (sourceCell != null) {                    CellStyle style = sourceCell.getCellStyle();                    targetCell.setCellStyle(style);                }            }        }    }

// 获取指定列的日期数据    private static List<Date> getColumnValues(Sheet sheet) {        List<Date> columnValues = new ArrayList<>();

    for (int rowIndex = 0; rowIndex <= sheet.getLastRowNum(); rowIndex++) {            Row row = sheet.getRow(rowIndex);

        if (row != null) {                Cell cell = row.getCell(0);

            if (cell != null && cell.getCellType() == CellType.NUMERIC) {                    columnValues.add(cell.getDateCellValue());                }            }        }

    return columnValues;    }

// 在日期数据中插入中间值,直至相邻日期间隔小于10天    private static List<Date> insertDates(List<Date> dates) {        List<Date> newDates = new ArrayList<>(dates);        int originalSize = newDates.size();        int maxSize = originalSize * 2; // 设置插入的日期数量阈值        int insertCount = 0; // 插入计数器

    for (int i = 0; i < newDates.size() - 1; i++) {            Date currentDate = newDates.get(i);            Date nextDate = newDates.get(i + 1);

        long interval = (nextDate.getTime() - currentDate.getTime()) / (24 * 60 * 60 * 1000);

        if (interval > 10) { // 修改条件为大于10天                while (interval > 10 && newDates.size() < maxSize && insertCount < 100) { // 修改条件为大于10天,并添加日期数量限制条件和插入计数器                    Date middleDate = new Date((currentDate.getTime() + nextDate.getTime()) / 2);                    if (!newDates.contains(middleDate)) {                        newDates.add(i + 1, middleDate);                        insertCount++;                    }                    interval = (nextDate.getTime() - middleDate.getTime()) / (24 * 60 * 60 * 1000);                    nextDate = newDates.get(i + 2); // 更新相邻日期                }            }        }

    return newDates;    }

// 将日期数据写入指定列    private static void writeColumnValues(Sheet sheet, List<Date> dates) {        SimpleDateFormat dateFormat = new SimpleDateFormat('yyyy-MM-dd hh:mm');

    for (int rowIndex = 0; rowIndex < dates.size(); rowIndex++) {            Row row = sheet.getRow(rowIndex);

        if (row == null) {                row = sheet.createRow(rowIndex);            }

        Cell cell = row.createCell(0);            cell.setCellValue(dateFormat.format(dates.get(rowIndex)));        }    }}

此代码尝试在间隔超过 10 天的日期之间插入日期。但是,while 循环中缺少适当的终止条件可能会导致无限循环。

解决方案

为了防止无限循环,请在 while 循环中实现一个健壮的终止条件。这可以通过以下方式实现:

  1. **限制插入次数:**引入一个计数器来跟踪插入次数,并在达到预定义限制时中断循环。

  2. **检查日期是否已存在:**在插入日期之前,请检查该日期是否已存在于列表中。如果日期已存在,则跳过插入以避免无限循环。

改进后的代码java// 在日期数据中插入中间值,直至相邻日期间隔小于10天private static List insertDates(List dates) { List newDates = new ArrayList<>(dates); int maxInsertCount = 100; // 限制最大插入次数 int insertCount = 0; // 插入计数器

for (int i = 0; i < newDates.size() - 1; i++) {        Date currentDate = newDates.get(i);        Date nextDate = newDates.get(i + 1);

    long interval = (nextDate.getTime() - currentDate.getTime()) / (24 * 60 * 60 * 1000);

    if (interval > 10) {            while (interval > 10 && insertCount < maxInsertCount) {                Date middleDate = new Date((currentDate.getTime() + nextDate.getTime()) / 2);                // 检查日期是否已存在                if (!newDates.contains(middleDate)) {                     newDates.add(i + 1, middleDate);                    insertCount++;                } else {                    // 如果日期已存在,则跳出循环                    break;                 }                interval = (nextDate.getTime() - middleDate.getTime()) / (24 * 60 * 60 * 1000);                nextDate = newDates.get(i + 2);            }        }    }

return newDates;}

通过添加这些保护措施,确保了日期插入过程最终终止,从而防止了潜在的无限循环并使代码更加健壮和高效。

Java Apache POI 日期插入优化:解决 Excel 数据处理死循环

原文地址: https://www.cveoy.top/t/topic/fTDa 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录