2

我正在使用 POI 的事件 API 来处理大量记录,而没有任何内存占用问题。是它的参考。

当我处理 XLSX 表时,我得到的日期值格式与 Excel 表中指定的格式不同。Excel 工作表中列的日期格式是“dd-mm-yyyy”,因为我得到的值是“mm/dd/yy”格式。

有人可以告诉我如何获得 excel 表中给出的实际格式。下面给出了代码片段的参考。

ContentHandler handler = new XSSFSheetXMLHandler(styles, strings,
          new SheetContentsHandler() {
            public void startRow(int rowNum) {
            }
            public void endRow() {
            }
            public void cell(String cellReference, String formattedValue) {
                  System.out.println(formattedValue);
                } catch (IOException e) {
                    System.out.println(
                      "Exception during file writing");
                }
              }

在日期列的单元格方法中获取 formattedValue 就像“mm/dd/yy”,因此我无法在我的 pl/sql 程序中正确进行验证。

4

3 回答 3

5

要记住两点:

  1. 原始 Excel 单元格的格式可能不适合您,或者可能被格式化为一般文本。
  2. 您可能希望准确控制日期、时间或数值的格式。

控制日期格式和其他数值的另一种方法是提供您自己的自定义DataFormatter 扩展 org.apache.poi.ss.usermodel.DataFormatter。

您只需覆盖 formatRawCellContents() 方法(或其他方法,具体取决于您的需要):

构造解析器/处理程序的示例代码:

public void processSheet(Styles styles, SharedStrings strings,
        SheetContentsHandler sheetHandler, InputStream sheetInputStream)
        throws IOException, SAXException {
    DataFormatter formatter = new CustomDataFormatter();
    InputSource sheetSource = new InputSource(sheetInputStream);
    try {
        XMLReader sheetParser = SAXHelper.newXMLReader();
        ContentHandler handler = new XSSFSheetXMLHandler(styles, null, strings, sheetHandler,
                formatter, false);
        sheetParser.setContentHandler(handler);
        sheetParser.parse(sheetSource);
    } catch (ParserConfigurationException e) {
        throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
    }
}

private class CustomDataFormatter extends DataFormatter {

    @Override
    public String formatRawCellContents(double value, int formatIndex, String formatString,
            boolean use1904Windowing) {

        // Is it a date?
        if (DateUtil.isADateFormat(formatIndex, formatString)) {
            if (DateUtil.isValidExcelDate(value)) {
                Date d = DateUtil.getJavaDate(value, use1904Windowing);
                try {
                    return new SimpleDateFormat("yyyyMMdd").format(d);
                } catch (Exception e) {
                    logger.log(Level.SEVERE, "Bad date value in Excel: " + d, e);
                }
            }
        }
        return new DecimalFormat("##0.#####").format(value);
    }
}
于 2018-11-15T18:09:15.140 回答
4

我有同样的问题。经过几天的谷歌搜索和研究,我想出了一个解决方案。不幸的是,它并不好,但它有效:

  1. org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler在您的项目中制作类的副本。
  2. 在类中找到接口SheetContentsHandler
  3. 添加一个新的方法定义:String overriddenFormat(String cellRef, int formatIndex, String formatString);
  4. 在类中找到这个方法:public void endElement(String uri, String localName, String name) throws SAXException.
  5. 它对细胞类型的切换时间很长。
  6. 在这种情况下NUMBER,有这样的 if 语句:if (this.formatString != null) {...
  7. 在此之前,粘贴此代码:

    String overriddenFormat = output.overriddenFormat(cellRef, formatIndex, formatString);
    if (overriddenFormat != null) {
        this.formatIndex = -1;
        this.formatString = overriddenFormat;
    }
    
  8. 按照这篇文章/答案:https ://stackoverflow.com/a/11345859但使用您的新类和接口。

  9. 现在,如果需要,您可以使用独特的日期格式。

我的用例是:在给定的工作表中,我在 G、H 和 I 列中有日期值,所以我的实现SheetContentsHandler.overriddenFormat是:

@Override
public String overriddenFormat(String cellRef, int formatIndex, String formatString) {
    if (cellRef.matches("(G|H|I)\\d+")) { //matches all cells in G, H, and I columns
        return "yyyy-mm-dd;@"; //this is the hungarian date format in excel
    }
    return null;
}

如您所见,在该endElement方法中,我已经覆盖了 formatIndex 和 formatString。formatIndex 的可能值在 中描述org.apache.poi.ss.usermodel.DateUtil.isInternalDateFormat(int format)。如果给定的值不适合这些(并且 -1 不适合),则将通过格式化时间戳值来使用 formatString。(时间戳值从大约 1900.01.01 开始计算,并具有日分辨率。)

于 2013-10-14T09:03:32.540 回答
2

Excel 存储一些带有区域设置的日期。例如,在 Excel 中的数字格式对话框中,您将看到如下警告:

根据您指定的类型和语言环境(位置),将日期和时间序列号显示为日期值。以星号 (*) 开头的日期格式会响应控制面板中指定的区域日期和时间设置的更改。没有星号的格式不受控制面板设置的影响。

您正在阅读的 Excel 文件可能正在使用这些 * 日期之一。在这种情况下,POI 可能使用美国默认值。

您可能需要添加一些解决方法代码来将日期格式字符串映射到您想要的格式。

有关Excel中区域日期设置的讨论,另请参见下文。

于 2013-06-26T11:24:28.273 回答