Java 获取行索引时的XmlValueDisconnectedException(getRowNum())

Java 获取行索引时的XmlValueDisconnectedException(getRowNum()),java,exception,apache-poi,row,Java,Exception,Apache Poi,Row,在我的代码中,我将逐行查看一个XLSX文件,并使用ApachePOI4.1.0在数据库中验证它们。如果我发现一个不正确的行,我会通过将其添加到列表中以删除来“标记”它们。迭代每一行后,这个小方法应该删除标记为删除的行: ListIterator<XSSFRow> rowIterator = toRemove.listIterator(toRemove.size()); while (rowIterator.hasPrevious()) { XSSFRow row = row

在我的代码中,我将逐行查看一个XLSX文件,并使用ApachePOI4.1.0在数据库中验证它们。如果我发现一个不正确的行,我会通过将其添加到
列表中以删除
来“标记”它们。迭代每一行后,这个小方法应该删除标记为删除的行:

ListIterator<XSSFRow> rowIterator = toRemove.listIterator(toRemove.size());

while (rowIterator.hasPrevious()) {
    XSSFRow row = rowIterator.previous();
    if (row != null && row.getSheet() == sheet) {
        int lastRowNum = sheet.getLastRowNum();
        int rowIndex = row.getRowNum();

        if (rowIndex == lastRowNum) {
            sheet.removeRow(row);
        } else if (rowIndex >= 0 && rowIndex < lastRowNum) {
            sheet.removeRow(row);

        } else {
            System.out.println("\u001B[31mERROR: Removal failed because row " + rowIndex + " is out of bounds\u001B[0m");
        }
        System.out.println("Row " + rowIndex + " successfully removed");
    } else {
        System.out.println("Row skipped in removal because it was null already");
    }
}
编辑:我还尝试更改迭代过程(见下文),但错误保持不变

for (XSSFRow row : toRemove) {
   // same code as above without iterator and while
}

如果列表
toRemove
中包含一行,则会发生错误。
列表允许重复条目。因此,同一行可以双重添加到
列表中。如果然后
Iterator
获取该行的第一个匹配项,则该行将从工作表中正确删除。但是,如果同一行稍后再次出现,则
row.getRowNum()
会以这种方式失败,因为该行在工作表中不再存在

下面是复制该行为的完整代码:

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

import java.io.FileInputStream;
import java.io.FileOutputStream;

import java.util.*;

public class ExcelRemoveRows {

 public static void main(String[] args) throws Exception {

  String filePath = "Excel.xlsx"; // must contain at least 5 filled rows

  Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));
  Sheet sheet = workbook.getSheetAt(0);

  List<Row> toRemoveList = new ArrayList<Row>();
  toRemoveList.add(sheet.getRow(0));
  toRemoveList.add(sheet.getRow(2));
  toRemoveList.add(sheet.getRow(4));
  toRemoveList.add(sheet.getRow(2)); // this produces the error

  System.out.println(toRemoveList); // contains row hawing index 2 (r="3") two times

  for (Row row : toRemoveList) {
   System.out.println(row.getRowNum()); // XmlValueDisconnectedException on second occurance of row index 2
   sheet.removeRow(row);
  }

  FileOutputStream out = new FileOutputStream("Changed"+filePath);
  workbook.write(out);
  out.close();
  workbook.close();
 }
}

您使用的是什么版本的ApachePOI?如果不是最新版本,升级时会发生什么情况?如果
列表中的一行是双行,则会发生错误。由于列表迭代器向后迭代,因此该行的最后一次出现将被成功删除。但是,如果以后再次出现同一行,则
row.getRowNum()
会以这种方式失败,因为该行在工作表中不再存在。现在,您可以检查所拥有的
对象是否与所拥有的
工作表
对象相关。即使该行已从图纸中删除,也可能是这样。删除将从图纸存储中删除该行。但这不会更新内存中已存储的所有相关对象。您需要避免在
列表中重复包含相同的行
以删除
。我不会在
列表中收集要删除的行,而是在
集合中收集要删除的行号。这将避免重复。然后,只需通过
sheet.getRow(rowNumber)
获取要删除的行。
import org.apache.poi.ss.usermodel.*;

import java.io.FileInputStream;
import java.io.FileOutputStream;

import java.util.*;

public class ExcelRemoveRows {

 public static void main(String[] args) throws Exception {

  String filePath = "Excel.xlsx"; // must contain at least 5 filled rows

  Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));
  Sheet sheet = workbook.getSheetAt(0);

  List<Row> toRemoveList = new ArrayList<Row>();
  toRemoveList.add(sheet.getRow(0));
  toRemoveList.add(sheet.getRow(2));
  toRemoveList.add(sheet.getRow(4));
  toRemoveList.add(sheet.getRow(2)); // this produces the error

  System.out.println(toRemoveList); // contains row hawing index 2 (r="3") two times

  for (Row row : toRemoveList) {
   System.out.println(row.getRowNum()); // XmlValueDisconnectedException on second occurance of row index 2
   sheet.removeRow(row);
  }

  FileOutputStream out = new FileOutputStream("Changed"+filePath);
  workbook.write(out);
  out.close();
  workbook.close();
 }
}
...
  Set<Integer> toRemoveSet = new HashSet<Integer>();
  toRemoveSet.add(sheet.getRow(0).getRowNum());
  toRemoveSet.add(sheet.getRow(2).getRowNum());
  toRemoveSet.add(sheet.getRow(4).getRowNum());
  toRemoveSet.add(sheet.getRow(2).getRowNum());

  System.out.println(toRemoveSet); // does not contain the row index 2 two times

  for (Integer rowNum : toRemoveSet) {
   Row row = sheet.getRow(rowNum);
   System.out.println(row.getRowNum());
   sheet.removeRow(row);
  }
...