如何使用Apache POI在Java中读取Excel合并单元格?

16

我有一个以 .xlsx 格式存储的 Excel 文件。我通过合并单元格来组成不同的列存储数据。我通过 Java web 应用程序读取 Excel 文件并将其数据保存到数据库(MySQL)。但是当我从合并的单元格中读取时,我得到了 null 值,同时也得到了存储在列和标题中的值。我使用 Apache POI。我的代码如下:

public static void excelToDBLogIN() {

    FileInputStream file = null;
    Boolean flag = true;
    ArrayList<String> rows = new ArrayList<String>();
    try {


        // here uploadFolder contains the path to the Login 3.xlsx file

        file = new FileInputStream(new File(uploadFolder + "Login 3.xlsx"));

        //Create Workbook instance holding reference to .xlsx file
        XSSFWorkbook workbook = new XSSFWorkbook(file);

        //Get first/desired sheet from the workbook
        XSSFSheet sheet = workbook.getSheetAt(0);

        //Iterate through each rows one by one
        Iterator<Row> rowIterator = sheet.iterator();


        while (rowIterator.hasNext()) {
            Row row = rowIterator.next();

            //For each row, iterate through all the columns
            Iterator<Cell> cellIterator = row.cellIterator();

            String tuple = "";
            while (cellIterator.hasNext()) {
                Cell cell = cellIterator.next();

                //Check the cell type and format accordingly
                switch (cell.getCellType()) {

                        case Cell.CELL_TYPE_NUMERIC:                            

                        //int value = new BigDecimal(cell.getNumericCellValue()).setScale(0, RoundingMode.HALF_UP).intValue();
                        //tuple = tuple + String.valueOf(value) + "+";

                        DataFormatter objDefaultFormat = new DataFormatter();    

                        String str = objDefaultFormat.formatCellValue(cell);

                        tuple = tuple + str + "+";

                        break;

                    case Cell.CELL_TYPE_STRING:

                        tuple = tuple + cell.getStringCellValue() + "+";

                        break;

                    case Cell.CELL_TYPE_BLANK:                                                        

                        tuple = tuple + "" + "+";

                        break;


                }

            }

            rows.add(tuple);
            flag = true;

        }

    }    


    } catch (Exception e) {

        e.printStackTrace();

    } finally {

        if (file != null) {

            try {
                file.close();
                file = null;
            } catch (Exception e) {

                System.out.println("File closing operation failed");
                e.printStackTrace();
            }
        }                                 

    }

    }

}

我在网上搜索答案,但没有找到任何相关的内容。


3
合并单元格很不好,不应该被允许使用。请避免使用它们。通常情况下,Excel会将合并区域的内容存储在该区域左上角的单元格中,其他单元格将返回0。 - teylyn
尝试这个:https://dev59.com/UnbZa4cB1Zd3GeqPEEpJ#27799327 - Sankumarsingh
1
我知道,但 Excel 格式是由学院部门制定的。我们的项目只是从他们那里获取信息并更新数据库。个人而言,我本来会避免使用这些格式。 - Saber
@teylyn 有没有特别的原因,为什么合并单元格不好? - EMM
@EMM 是的。它们会破坏事情。将A3合并到D3。现在尝试选择C1到C5。或者使用循环将某些内容写入C1到C5。看看为什么这是不好的? - teylyn
2个回答

14

以下代码片段可能会有所帮助。

while (rowIterator.hasNext()) {
        Row row = rowIterator.next();

        //For each row, iterate through all the columns
        Iterator<Cell> cellIterator = row.cellIterator();

        outer:
        while (cellIterator.hasNext()) {
            Cell cell = cellIterator.next();

            //will iterate over the Merged cells
            for (int i = 0; i < sheet.getNumMergedRegions(); i++) {
                CellRangeAddress region = sheet.getMergedRegion(i); //Region of merged cells

                int colIndex = region.getFirstColumn(); //number of columns merged
                int rowNum = region.getFirstRow();      //number of rows merged
                //check first cell of the region
                if (rowNum == cell.getRowIndex() && colIndex == cell.getColumnIndex()) {
                    System.out.println(sheet.getRow(rowNum).getCell(colIndex).getStringCellValue());
                    continue outer;
                }
            }
            //the data in merge cells is always present on the first cell. All other cells(in merged region) are considered blank
            if (cell.getCellType() == Cell.CELL_TYPE_BLANK || cell == null) {
                continue;
            }
            System.out.println(cell.getStringCellValue());
        }
    }

1
谢谢,但我决定在Excel中使用未合并的单元格。其他人,包括这里的人,都建议不要使用合并单元格的Excel文件来提供数据给应用程序。 - Saber
2
@Deepika 如果文件中没有合并的列,那么代码会起作用吗? - Labeo
代码运行良好,即使没有合并的列也可以。但是单元格迭代器仅获取具有非空值的单元格。我的要求是迭代每一列,无论它是空还是非空。 - Chetan Oswal

0

这个方法可以读取特定的单元格(包括合并单元格):

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.apache.poi.ss.usermodel.DateUtil;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;


public static void readCell(String excelFilePath, int rowIndex, int columnIndex) throws FileNotFoundException, IOException {
    try (InputStream inp = new FileInputStream(excelFilePath)) {
        XSSFWorkbook wb = new XSSFWorkbook(inp);
        XSSFCell cell = wb.getSheetAt(0).getRow(rowIndex).getCell(columnIndex);

        switch (cell.getCellType()) {

        case STRING:
            System.out.println(cell.getRichStringCellValue().getString());
            break;

        case NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                System.out.println(cell.getDateCellValue());
            } else {
                System.out.println(cell.getNumericCellValue());
            }
            break;

        case BOOLEAN:
            System.out.println(cell.getBooleanCellValue());
            break;

        case FORMULA:
            System.out.println(cell.getCellFormula());
            break;

        case BLANK:
            System.out.println();
            break;

        default:
            System.out.println();
        }

        wb.close();
    }
}

依赖项:POI 5.0.0,JDK 1.8.0


它究竟是什么呢?它是通过公式来工作的吗? - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接