首先POI没有提供删除列的API,所以就需要用其他的方式实现。
在 java - Apache POI xls column Remove - Stack Overflow 这里找到了实现方式:
先将该列所有值都清空,然后将该列之后的所有列往前移动。
下面的工具类中
deleteColumns(InputStream excelStream, List
- import lombok.SneakyThrows;
- import org.apache.poi.ss.usermodel.Cell;
- import org.apache.poi.ss.usermodel.Row;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.usermodel.Workbook;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-
- import java.io.ByteArrayOutputStream;
- import java.io.InputStream;
- import java.util.ArrayList;
- import java.util.List;
-
- /**
- * @Description
- * @ClassName ExcelUtil
- * @Date 2022/12/23 11:38
- */
- public class ExcelUtil {
-
- /**
- * 获取sheet表头
- * @param sheet
- * @return
- */
- public static List
getTitle(Sheet sheet) { - List
titleList = new ArrayList<>(); - if (sheet.getPhysicalNumberOfRows() > 0) {
- Row headerRow = sheet.getRow(0); // 获取第一行(表头行)
-
- for (int i = 0; i < headerRow.getPhysicalNumberOfCells(); i++) {
- Cell cell = headerRow.getCell(i);
- if (cell != null) {
- String headerText = cell.getStringCellValue();
- titleList.add(headerText);
- }
- }
- }
- return titleList;
- }
-
- /**
- * 删除excel指定列
- * @param excelStream excel流
- * @param delColumnTitleList 需要删除的列的表头
- * @return
- */
- @SneakyThrows
- public static ByteArrayOutputStream deleteColumns(InputStream excelStream, List
delColumnTitleList) { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-
- Workbook workbook = new XSSFWorkbook(excelStream);
- // 获取第一个sheet
- Sheet sheet = workbook.getSheetAt(0);
- deleteColumns(sheet, delColumnTitleList);
- workbook.write(outputStream);
- workbook.close();
- outputStream.close();
- return outputStream;
- }
-
- /**
- * 删除sheet指定的列
- * @param sheet
- * @param delColumnTitleList
- */
- public static void deleteColumns(Sheet sheet, List
delColumnTitleList) { - List
titleList = getTitle(sheet); - for (String delTitle : delColumnTitleList) {
- int i = titleList.indexOf(delTitle);
- if (i >= 0) {
- deleteColumn(sheet, i);
- }
- //由于是循环删除,删除后,列所在位置索引会变化,所以titleList相应也移除删除的列
- titleList.remove(delTitle);
- }
- }
-
- /**
- * 删除指定列
- * poi没有提供删除指定列的api,所以先将该列清空,然后将后续的列往前移动,这样达到删除列的效果
- * @param sheet
- * @param columnToDelete
- */
- public static void deleteColumn(Sheet sheet, int columnToDelete) {
- int maxColumn = 0;
- for (int r = 0; r < sheet.getLastRowNum() + 1; r++) {
- Row row = sheet.getRow(r);
-
- // if no row exists here; then nothing to do; next!
- if (row == null) {
- continue;
- }
-
- // if the row doesn't have this many columns then we are good; next!
- int lastColumn = row.getLastCellNum();
- if (lastColumn > maxColumn) {
- maxColumn = lastColumn;
- }
-
- if (lastColumn < columnToDelete) {
- continue;
- }
-
- for (int x = columnToDelete + 1; x < lastColumn + 1; x++) {
- Cell oldCell = row.getCell(x - 1);
- if (oldCell != null) {
- row.removeCell(oldCell);
- }
-
- Cell nextCell = row.getCell(x);
- if (nextCell != null) {
- Cell newCell = row.createCell(x - 1, nextCell.getCellType());
- cloneCell(newCell, nextCell);
- }
- }
- }
-
- // Adjust the column widths
- for (int c = 0; c < maxColumn; c++) {
- sheet.setColumnWidth(c, sheet.getColumnWidth(c + 1));
- }
- }
-
- /**
- * 右边列左移
- */
- private static void cloneCell(Cell cNew, Cell cOld) {
- cNew.setCellComment(cOld.getCellComment());
- cNew.setCellStyle(cOld.getCellStyle());
-
- switch (cNew.getCellTypeEnum()) {
- case BOOLEAN: {
- cNew.setCellValue(cOld.getBooleanCellValue());
- break;
- }
- case NUMERIC: {
- cNew.setCellValue(cOld.getNumericCellValue());
- break;
- }
- case STRING: {
- //这样不丢样式
- cNew.setCellValue(cOld.getRichStringCellValue());
- break;
- }
- case ERROR: {
- cNew.setCellValue(cOld.getErrorCellValue());
- break;
- }
- case FORMULA: {
- cNew.setCellFormula(cOld.getCellFormula());
- break;
- }
- }
-
- }
-
- }