【问题标题】:Java POI Exporting to excel with empty row is ignored when importing it导入时忽略Java POI导出到空行的excel
【发布时间】:2014-09-03 09:06:49
【问题描述】:

我有使用 Apache POI lib 导出/导入 excel 文件 (.xls) 的 java 程序(我正在为旧的 excel .xls 文件使用 HSSF 前缀类)。

我的excel格式是:
第 1 行:标题
第 2 行:空
第 3 行:带有标题和内容的表格

假设我的表有 5 行,包括标题,因此总共 7 行。 我正在将数据导出到一个 excel 文件,文件大小为 6k。 在不更改文件中的任何内容的情况下,我正在导入它,并且在调试导入时我意识到我的行数是 6!这意味着由于某种我不明白的原因,它会忽略空行。

下一个场景,我导出文件用 MS Excel 打开它保存它,文件大小更改为 24k。 我执行导入并且它有效,行的总大小再次为 7。
导入代码的导出和开始如下:

public static TempFile createExcelFile(String sheetTitle, String title, String headerSummary, List<String> header, List<LinkedHashMap<String, String>> data)
{
    TempFile result = new TempFile(FileKeyFactory.getFileKey(ExcelReporter.class).getFullPathKey());
    HSSFWorkbook wb = new HSSFWorkbook();
    HSSFSheet spreadSheet;
    DataFormat format = null;
    int rowIndex = 0;

    // Get a DataFormat object and use it to create a CellStyle object
    // with the following format set for the cells @. The @ or ampersand
    // sets the format so that the cell will hold text.
    format = wb.createDataFormat();

    if (sheetTitle != null)
    {
        spreadSheet = wb.createSheet(sheetTitle);
    }
    else
    {
        spreadSheet = wb.createSheet();
    }

    if (title != null)
    {
        // Title
        HSSFFont titleFont = wb.createFont();
        titleFont.setFontHeightInPoints((short) 14);
        titleFont.setItalic(true);
        HSSFRow titleRow = spreadSheet.createRow(rowIndex++);
        HSSFCell cell = titleRow.createCell(0);
        cell.setCellValue(title);
        cell.getCellStyle().setFont(titleFont);
        spreadSheet.addMergedRegion(new CellRangeAddress(0, 0, 0, 100));
    }
    else
    {
        spreadSheet = wb.createSheet();
    }

    HSSFCellStyle style = wb.createCellStyle();
    style.setDataFormat(format.getFormat("@"));

    if (headerSummary != null)
    {
        HSSFFont headerFont = wb.createFont();
        headerFont.setFontHeightInPoints((short) 9);
        headerFont.setItalic(false);

        HSSFCellStyle headerCellStyle = wb.createCellStyle();
        headerCellStyle.setDataFormat(format.getFormat("@"));
        headerCellStyle.setFont(headerFont);
        headerCellStyle.setWrapText(true);

        HSSFRow headerRow = spreadSheet.createRow(rowIndex++);
        HSSFCell headerCell = headerRow.createCell(0);

        headerCell.setCellValue(headerSummary);
        headerCell.setCellStyle(headerCellStyle);
        //increase row height to accommodate two lines of text
        headerRow.setHeightInPoints((9 * spreadSheet.getDefaultRowHeightInPoints()));

        //adjust column width to fit the content
        spreadSheet.autoSizeColumn((short) 1);
        spreadSheet.addMergedRegion(new CellRangeAddress(1, 1, 0, 100));
    }


    /*
     * Data table header
     */
    HSSFRow dateRow = spreadSheet.createRow(rowIndex++);
    Calendar calendar = Calendar.getInstance();
    HSSFCreationHelper createHelper = wb.getCreationHelper();
    CellStyle cellStyle = wb.createCellStyle();
    cellStyle.setDataFormat(createHelper.createDataFormat().getFormat("m/d/yy h:mm"));
    HSSFCell cell = dateRow.createCell(0);
    cell.setCellValue("Created: " + DateParser.toString(calendar, DateParser.MONTH_WORD_DATE_FORMAT));
    cell.setCellStyle(cellStyle);

    HSSFFont headerTableFont = wb.createFont();
    headerTableFont.setFontHeightInPoints((short) 10);
    headerTableFont.setColor(IndexedColors.WHITE.getIndex());

    HSSFCellStyle tableHeaderStyle = wb.createCellStyle();
    tableHeaderStyle.setDataFormat(format.getFormat("@"));
    tableHeaderStyle.setBorderRight(HSSFCellStyle.BORDER_MEDIUM);
    tableHeaderStyle.setBorderTop(HSSFCellStyle.BORDER_MEDIUM);
    tableHeaderStyle.setBorderLeft(HSSFCellStyle.BORDER_MEDIUM);
    tableHeaderStyle.setBorderBottom(HSSFCellStyle.BORDER_MEDIUM);
    tableHeaderStyle.setFillForegroundColor(HSSFColor.LIGHT_BLUE.index);
    tableHeaderStyle.setFont(headerTableFont);
    tableHeaderStyle.setFillPattern(CellStyle.SOLID_FOREGROUND);

    HSSFRow tableHeaderRowRow = spreadSheet.createRow(rowIndex++);

    for (int i = 0; i < header.size(); i++)
    {
        HSSFCell ipHeaderCell = tableHeaderRowRow.createCell(i);
        ipHeaderCell.setCellStyle(tableHeaderStyle);
        ipHeaderCell.setCellValue(header.get(i));
        spreadSheet.autoSizeColumn(i);
    }

    /*
     * ********************** DATA *******************
     */
    HSSFCellStyle dataCellStyle = wb.createCellStyle();
    dataCellStyle.setDataFormat(format.getFormat("@"));
    dataCellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
    dataCellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
    dataCellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
    dataCellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);

    //spreadSheet.createRow(rowIndex++);
    for (LinkedHashMap<String, String> row : data)
    {
        HSSFRow currentRow = spreadSheet.createRow(rowIndex++);
        for (int i = 0; i < header.size(); i++)
        {
            HSSFCell dataCell = currentRow.createCell(i);
            dataCell.setCellStyle(dataCellStyle);
            dataCell.setCellType(Cell.CELL_TYPE_STRING);

            String celVal = row.get(header.get(i));
            dataCell.setCellValue(celVal);
        }
    }

    // Resize columns automatically.
    for (int i = 0; i < header.size(); i++)
    {
        spreadSheet.setDefaultColumnStyle(i, style);
        spreadSheet.autoSizeColumn(i);
    }

    FileOutputStream resultOutStream = null;
    try
    {
        resultOutStream = new FileOutputStream(result);
        wb.write(resultOutStream);
        resultOutStream.flush();
    }
    catch (Exception e)
    {
        Logger.ERROR("File path: " + result.getAbsolutePath() + File.separator + result.getName(), e);
        throw new RuntimeException("File path: " + result.getAbsolutePath() + File.separator + result.getName(), e);
    }
    finally
    {
        try
        {
            if (resultOutStream != null)
            {
                resultOutStream.close();
            }
        }
        catch (Exception ignore)
        {

        }
    }

    return result;
}

public void import()
{
    ...
    InputStream input = new BufferedInputStream(new FileInputStream(file));
    POIFSFileSystem fs = new POIFSFileSystem(input);
    HSSFWorkbook wb = new HSSFWorkbook(fs);
    HSSFSheet sheet = wb.getSheetAt(0);

    Iterator rows = sheet.rowIterator();

    rows.next(); // skip title
    rows.next(); // skip empty row
    List<String> header = getLine((HSSFRow) rows.next());
    ...
}

private List<String> getLine(HSSFRow row)
{
    List<String> header = new ArrayList<String>();
    Iterator<Cell> cellIterator = row.cellIterator();

    while(cellIterator.hasNext())
    {
        HSSFCell cell = (HSSFCell)cellIterator.next();
        cell.setCellType(Cell.CELL_TYPE_STRING);
        header.add(cell.toString());
    }

    return header;
} 


知道为什么在再次导出和导入后,调用 sheet.rowIterator() 时会忽略空行吗?

【问题讨论】:

    标签: java excel apache-poi


    【解决方案1】:

    这是预期的行为。来自Javadocs:

    返回物理行的迭代器。这意味着如果第二行未定义,则第三个元素可能不是第三行。

    如果您查看Apache POI documentation on iterating over rows and cells,您会看到更详细的描述,以及有关如何在一个范围内的所有行上强制迭代的说明(如果这是您真正想要的)。您的代码将类似于(取自 Apache POI 文档)

    // Decide which rows to process
    int rowStart = Math.min(15, sheet.getFirstRowNum());
    int rowEnd = Math.max(1400, sheet.getLastRowNum());
    
    for (int rowNum = rowStart; rowNum < rowEnd; rowNum++) {
       Row r = sheet.getRow(rowNum);
       if (r == null) {
          // Handle empty row
          continue;
       }
    
       int lastColumn = Math.max(r.getLastCellNum(), MY_MINIMUM_COLUMN_COUNT);
    
       for (int cn = 0; cn < lastColumn; cn++) {
          Cell c = r.getCell(cn, Row.RETURN_BLANK_AS_NULL);
          if (c == null) {
             // The spreadsheet is empty in this cell
          } else {
             // Do something useful with the cell's contents
          }
       }
    }
    

    【讨论】:

    • 这很有趣,尽管我不希望将工作表限制为硬编码的最小/最大行。
    • 我检查了你的代码。我不需要最小值/最大值,因为我知道我总是从零开始,我只需要最后一行,它对我有用。谢谢。
    【解决方案2】:

    我从未遇到过这个问题,但我使用的是 sheet.getRow(row) 而不是 rowIterator()。我猜这可能是 POI 中的 rowIterator 实现中的一个错误(您应该向他们报告)。

    那么请您尝试更改您的代码:

    Iterator rows = sheet.rowIterator();
    rows.next(); // skip title
    rows.next(); // skip empty row
    List<String> header = getLine((HSSFRow) rows.next());
    

    收件人:

    int row = 0;
    ++row;  // skip title;
    ++row;  // skip empty row
    List<String> header = getLine((HSSFRow)sheet.getRow(row)); ++row;
    

    希望它有效。

    注意:您还应该使用“Workbook”、“Sheet”和“Row”而不是“HSSFWorkbook”、“HSSFSheet”和“HSSFRow”。这将为您节省一些输入,并且您的代码将准备就绪,以防您需要有一天处理一些 XLSX 文件!

    【讨论】:

    • 这不是错误,这是行迭代器的预期和记录行为
    猜你喜欢
    • 1970-01-01
    • 2014-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-27
    • 2019-08-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多