java poi对Excel表格进行单元行删除
前几天工作时,突然需要去使用POI 来对Excel 表格进行操作,其他的操作都都没什么问题,但是在需要删除某些单元行的时候碰到了一下小坑,记录下来,防止以后忘记。
一般使用POI删除单元行有两种方法
一种只删除单元行中的内容,不删除单元行
即 sheet.removeRow(row); //sheet即取得的工作表,row表示要具体删除的行
这个方法没什么问题
第二种就是实现删除整个单元行
即 sheet.shiftRows(1, 4, -1); //意思是 从 第一行开始,到第四行,整个的移动(-1)行,即上移一行
可以看到,我用的是移动,而不是删除。
如果你想要删除的那一个单元行里面具备合并单元格,而他的下一行不具备相同的合并单元格,那你就会发现你下行的数据丢失了。
原因就是因为shiftRows这个方法并不是真正的删除单元行!
而是通过移动下面的单元行中的内容上来,覆盖原先的内容,以此来做到类似于删除单元行的样子,但是并不会对合并单元格有影响。
如果你想要删除的单元行与它下面一行的单元格具备不同的合并单元格,那么就会出现影响。
网上找了半天也没有解决办法。
只能自己想法子解决,
解决思路。
让想要删除的单元行与下一行中的单元格格式相同。
首先取得下面一行单元格的格式。(如果下一行中不具备合并单元格,则不需要这一步也可以,如果要删除多行,只要去要删除的最后一行,下面一行的格式即可)
private List<Map<Integer, Integer>> reginMapList(Row row, int columnIndex) {
//第一个integer代表起始列数,第二个integer 代表结束列数
//保存指定行的 全部合并单元格的格式,非合并单元格不包存
List<Map<Integer, Integer>> mapList = new ArrayList<>();
Sheet sheet = row.getSheet();
int numMergedRegions = sheet.getNumMergedRegions();
int rowIndex = row.getRowNum();
int firstC;
int lastC;
int firstR;
int lastR;
//POI中取得所有的合并单元格 ,顺序是乱的,而不是冲上到下
for (i = 0; i < numMergedRegions; i++) {
CellRangeAddress cellRangeAddress = sheet.getMergedRegion(i);
// 获得合并单元格的起始行, 结束行, 起始列, 结束列
firstC = cellRangeAddress.getFirstColumn();
lastC = cellRangeAddress.getLastColumn();
firstR = cellRangeAddress.getFirstRow();
lastR = cellRangeAddress.getLastRow();
//当合并单元格行数与指定行相同 ,且指定列数大于或等于单元格起始列时
while (firstR == rowIndex && columnIndex <= firstC) {
//判断是否属于合并单元格
if (columnIndex <= lastC && columnIndex >= firstC && rowIndex <= lastR && rowIndex >= firstR) {
Map<Integer, Integer> map = new HashMap<>();
map.put(firstC, lastC);
mapList.add(map);
columnIndex = 1;
break;
} else {
columnIndex++;
}
}
}
return mapList;
}
之后删除需要删除的单元行的合并单元格格式
private void deleteRegion(Sheet sheet, int begRow, int endRow, int begCol, int endCol) {
//如果指定位置是合并单元格则删除(仅删除一个)
//这里是针对我自己的情况
//如果要删除一行多个合并单元格,还需要自己去修改
int count = sheet.getNumMergedRegions();
for (int i = 0; i < count; i++) {
CellRangeAddress rangeAddress = sheet.getMergedRegion(i);
if (rangeAddress == null) {
continue;
}
int fistRow = rangeAddress.getFirstRow();
int lastRow = rangeAddress.getLastRow();
int fistCol = rangeAddress.getFirstColumn();
int lastCol = rangeAddress.getLastColumn();
if (fistRow >= begRow && lastRow <= endRow && fistCol >= begCol && lastCol <= endCol) {
sheet.removeMergedRegion(i);
}
}
}
然后将已经恢复到不具备合并单元格的这行 按照下面一行的格式进行单元格合并,方便删除。
private void cellRegin(Sheet sheet, Row mainRow, List<Map<Integer, Integer>> mapList) {
//mainRow 进行合并单元格的行
sheet.removeRow(mainRow);//先把内容删了,防止之后多出数据
if (mapList.size() > 0) {
for (Map<Integer, Integer> map : mapList) {
for (Integer begCol : map.keySet()) {
mergedRegion(sheet, new TableRegion(mainRow.getRowNum(), mainRow.getRowNum(), begCol, map.get(begCol)));
}
}
}
}
最后就可以对该行进行删除
sheet.shiftRows(mainRowNum +1, sheet.getLastRowNum(), - 1);//从下行到最后一行 全部上移一行,覆盖该行的内容
这个解决方法比较复杂,但目前也没想到什么其他方法,主要是POI中本身也没有提供删除单元行内容的办法