我需要将两个工作表与Apache POI进行比较。 有没有一种简单的方法可以做到这一点,例如工作表比较功能,或者我必须比较每个单元格?
由于这是Google上关于比较POI工作簿的第一个问题之一,因此我想分享一个适用于单元测试的解决方案。我找到了一个好的Hamcrest匹配器来解决这个问题:
http://baddotrobot.com/blog/2012/09/14/diff-excel-with-java-and-hamcrest/
基本上,通过Maven导入库(详见Github自述文件)。拥有两个 POI 工作簿后,您可以编写类似于以下内容的断言:
MatcherAssert.assertThat("Workbooks to be identical", actualWorkbook,
WorkbookMatcher.sameWorkbook(expectedWorkbook));
注意:我在这里使用MatcherAssert来检索有关比较的更详细的注释,但JUnit Assert也可以使用。这在作者的网站上有所说明。
它可以在GitHub上找到,也可以通过作者的个人Maven存储库获得。
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.junit.Assert;
public class CompareExcel {
public static void assertWorkbooksEqual(final XSSFWorkbook workbookA, final XSSFWorkbook workbookB) {
for (int i = 0; i < workbookA.getNumberOfSheets(); i++) {
final XSSFSheet sheetA = workbookA.getSheetAt(i);
final XSSFSheet sheetB = workbookB.getSheetAt(i);
compareTwoSheets(sheetA, sheetB);
}
}
private static void compareTwoSheets(final XSSFSheet sheetA, final XSSFSheet sheetB) {
final int firstRowA = sheetA.getFirstRowNum();
final int lastRowB = sheetA.getLastRowNum();
final String sheetName = sheetA.getSheetName();
Assert.assertEquals(sheetName, sheetB.getSheetName());
Assert.assertEquals("In sheet: " + sheetName, firstRowA, sheetB.getFirstRowNum());
Assert.assertEquals("In sheet: " + sheetName, lastRowB, sheetB.getLastRowNum());
for(int i=firstRowA; i <= lastRowB; i++) {
final XSSFRow rowA = sheetA.getRow(i);
final XSSFRow rowB = sheetB.getRow(i);
compareTwoRows(sheetName, rowA, rowB);
}
}
private static void compareTwoRows(final String sheetName, final XSSFRow rowA, final XSSFRow rowB) {
if((rowA == null) && (rowB == null)) {
return;
}
Assert.assertNotNull("In sheet: " + sheetName, rowA);
Assert.assertNotNull("In sheet: " + sheetName, rowB);
final int firstCellA = rowA.getFirstCellNum();
final int lastCellA = rowA.getLastCellNum();
Assert.assertEquals("In sheet: " + sheetName, firstCellA, rowB.getFirstCellNum());
Assert.assertEquals("In sheet: " + sheetName, lastCellA, rowB.getLastCellNum());
for(int i=firstCellA; i <= lastCellA; i++) {
final XSSFCell cellA = rowA.getCell(i);
final XSSFCell cellB = rowB.getCell(i);
compareTwoCells(sheetName, cellA, cellB);
}
}
private static void compareTwoCells(final String sheetName, final XSSFCell cellA, final XSSFCell cellB) {
if((cellA == null) && (cellB == null)) {
return;
}
Assert.assertNotNull(cellA);
Assert.assertNotNull(cellB);
String valueA = null;
String valueB = null;
Assert.assertEquals(cellA.getCellTypeEnum(), cellB.getCellTypeEnum());
switch(cellA.getCellTypeEnum()) {
case NUMERIC:
valueA = String.valueOf(cellA.getNumericCellValue());
valueB = String.valueOf(cellB.getNumericCellValue());
break;
case STRING:
valueA = cellA.getStringCellValue();
valueB = cellB.getStringCellValue();
break;
default:
Assert.fail(
String.format(
"Unexpected cell type '%s' in sheet: '%s' row: '%s' column: '%s'",
cellA.getCellTypeEnum().name(),
sheetName,
cellA.getRowIndex(),
cellA.getColumnIndex()
));
}
Assert.assertEquals(
String.format(
"Cell values do not match in sheet: '%s' row: '%s' column: '%s'",
sheetName,
cellA.getRowIndex(),
cellA.getColumnIndex()
),
valueA, valueB);
}
}
尝试遍历所有单元格并计算运行哈希或类似的东西。您运行它两次,每个工作表一次,如果哈希相同 - 工作表相同。AFAIK,没有开箱即用的方法。
我相信这是一种比在单元格到单元格的基础上进行比较更好的方法,因为您一次只会打开一个工作表(而不是逐单元格方法中的两个工作表)。