Java 获取单元格值,以了解其在excel中的显示方式

Java 获取单元格值,以了解其在excel中的显示方式,java,apache-poi,Java,Apache Poi,我目前正在从事一个使用ApachePOI读取excel文件的项目 我的任务似乎很简单,我只需要获取excel文件中显示的单元格值。我知道根据单元的单元类型执行switch语句。但是如果数据是 9000.00 当我执行getNumericCellValue()时,POI会给我9000.0。当我强制单元格为字符串类型并执行getStringCellValue()时,它会给出9000。我需要的是excel中显示的数据 我发现一些帖子告诉你使用DataFormat类,但据我所知,它要求你的代码知道单元格

我目前正在从事一个使用ApachePOI读取excel文件的项目

我的任务似乎很简单,我只需要获取excel文件中显示的单元格值。我知道根据单元的单元类型执行switch语句。但是如果数据是

9000.00

当我执行
getNumericCellValue()
时,POI会给我
9000.0
。当我强制单元格为字符串类型并执行
getStringCellValue()
时,它会给出
9000
。我需要的是excel中显示的数据

我发现一些帖子告诉你使用
DataFormat
类,但据我所知,它要求你的代码知道单元格的格式。在我的例子中,我不知道单元格可能具有的格式

那么,我如何才能检索单元格值,就像它在excel中的显示方式一样?

使用“您可以检查每件事”

if (cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC)
//单元格值是数值

if (cellValue.getCellType() == Cell.CELL_TYPE_STRING)
//cellValue是一个字符串

日期也以数字形式给出,此时使用


将单元格值转换为日期后,Excel将一些单元格存储为字符串,但大多数单元格存储为数字,并应用了特殊的格式规则。您需要做的是对数值单元格运行这些格式化规则,以生成与Excel中类似的字符串

幸运的是,Apache POI有一个类可以做到这一点-

您需要做的就是:

 Workbook wb = WorkbookFactory.create(new File("myfile.xls"));
 DataFormatter df = new DataFormatter();

 Sheet s = wb.getSheetAt(0);
 Row r1 = s.getRow(0);
 Cell cA1 = r1.getCell(0);

 String asItLooksInExcel = df.formatCellValue(cA1);

不管单元格类型是什么,DataFormatter都将使用Excel中应用的规则尽可能为您格式化。事实上,使用编写单元格时定义的区域设置,永远不可能准确获取格式化单元格值。这是因为存在区域设置观察者这样一个事实,即内部区域设置excel前缀在以后格式化时从未被重用

对POI 3.17的分析(在查看组件内部如何完成后可能会发生变化)

例如:Locale.US的单元格样式(来自CellStyle.getDataFormatString())的日期转换格式为dd MMM yyyy hh:mm:ss,格式为:
“[$-0409]dd-MMM-yyyy hh:mm:ss;@” 其中本地excel内部前缀=[$-0409]

它是从DateFormatConverter.localPrefixes私有静态映射中获得的

以下是解决此问题的一些代码:

/**
 * Missing method in POI to enable the visualisation asIs of an cell with a
 * different locale in a xls document.
 *
 * @param style
 *            the cell style localized.
 * @return the Locale found using internal locationPrefixes.
 */
private final Locale extractLocaleFromDateCellStyle(final CellStyle style) {

    final String reOpenedFormat = style.getDataFormatString();

    LOGGER.info("Data Format of CellStyle : " + reOpenedFormat);
    Locale locale = getLocaleFromPrefixes(extractPrefixeFromPattern(reOpenedFormat));
    LOGGER.info("Found locale : " + locale);
    return locale;
}

/**
 * Extracts the internal prefix that represent the local of the style.
 *
 * @param pattern
 *            the DataFormatString of the cell style.
 * @return the prefix found.
 */
private final String extractPrefixeFromPattern(final String pattern) {

    Pattern regex = Pattern.compile(REGEX_PREFIX_PATTERN);
    Matcher match = regex.matcher(pattern);

    if (match.find()) {
        LOGGER.info("Found prefix: " + match.group(1));
        // return only the prefix
        return match.group(1);
    }
    return null;
}

/**
 * Reverse obtain the locale from the internal prefix from
 * <code>DateFormatConverter.localePrefixes</code> private static field.
 * <p>
 * Uses reflection API.
 *
 * @param prefixes
 *            the prefixes
 * @return the local corresponding tho the prefixes.
 */
public static Locale getLocaleFromPrefixes(final String prefixes) {

    try {

        @SuppressWarnings("unchecked")
        Map<String, String> map = getStaticPrivateInternalMapLocalePrefix();

        String localPrefix = null;

        // find the language_Country value matching the internal excel
        // prefix.
        for (Map.Entry<String, String> entry : map.entrySet()) {

            LOGGER.info("value : " + entry.getValue() + ", key :"
                    + entry.getKey());

            if (entry.getValue().equals(prefixes)
                    && !StringUtils.isBlank(entry.getKey())) {
                localPrefix = entry.getKey();
                break;
            }
        }

        // Generate a Locale with language, uppercase(country) info.
        LOGGER.info(localPrefix);
        if (localPrefix.indexOf('_') > 0) {
            String[] languageCountry = localPrefix.split("_");
            return new Locale(languageCountry[0],
                    StringUtils.defaultString(languageCountry[1]
                            .toUpperCase()));
        }

        // nothing found.
        return null;

        // factorized the multiples exceptions.
    } catch (Exception e) {
        throw new UnsupportedOperationException(e);
    }

}

/**
 * gets the internal code map for locale used by Excel.
 * 
 * @return the internal map.
 * @throws NoSuchFieldException
 *             if the private field name changes.
 * @throws IllegalAccessException
 *             if the accessible is restricted.
 */
private static Map<String, String> getStaticPrivateInternalMapLocalePrefix()
        throws NoSuchFieldException, IllegalAccessException {
    // REFLECTION
    Class<?> clazz = DateFormatConverter.class;
    Field fieldlocalPrefixes = (Field) clazz
            .getDeclaredField(DATE_CONVERTER_PRIVATE_PREFIXES_MAP);

    // change from private to public.
    fieldlocalPrefixes.setAccessible(true);

    @SuppressWarnings("unchecked")
    Map<String, String> map = (Map<String, String>) fieldlocalPrefixes
            .get(clazz);

    LOGGER.info("MAP localPrefixes : " + map);
    return map;
}
因此,下面的简单代码应该可以做到这一点。 注意:代码没有针对空值进行完全测试,这取决于您使用的POI版本,直到它们在那里发生更改LOCALE OBSERVER MADNESS:)


关于。

我已经这样做了,我的问题是,数据的原始格式没有恢复。我试图通过getStringCellValue()获取字符串形式的数值。我得到了异常。只有我给了这个。这是否可以将字符串设置为数字。看一看,是的,我将单元格的单元格类型设置为字符串,但结果不准确。我已经在我的问题中说过了,我也在等待答案!谢谢
/**
 * Missing method in POI to enable the visualisation asIs of an cell with a
 * different locale in a xls document.
 *
 * @param style
 *            the cell style localized.
 * @return the Locale found using internal locationPrefixes.
 */
private final Locale extractLocaleFromDateCellStyle(final CellStyle style) {

    final String reOpenedFormat = style.getDataFormatString();

    LOGGER.info("Data Format of CellStyle : " + reOpenedFormat);
    Locale locale = getLocaleFromPrefixes(extractPrefixeFromPattern(reOpenedFormat));
    LOGGER.info("Found locale : " + locale);
    return locale;
}

/**
 * Extracts the internal prefix that represent the local of the style.
 *
 * @param pattern
 *            the DataFormatString of the cell style.
 * @return the prefix found.
 */
private final String extractPrefixeFromPattern(final String pattern) {

    Pattern regex = Pattern.compile(REGEX_PREFIX_PATTERN);
    Matcher match = regex.matcher(pattern);

    if (match.find()) {
        LOGGER.info("Found prefix: " + match.group(1));
        // return only the prefix
        return match.group(1);
    }
    return null;
}

/**
 * Reverse obtain the locale from the internal prefix from
 * <code>DateFormatConverter.localePrefixes</code> private static field.
 * <p>
 * Uses reflection API.
 *
 * @param prefixes
 *            the prefixes
 * @return the local corresponding tho the prefixes.
 */
public static Locale getLocaleFromPrefixes(final String prefixes) {

    try {

        @SuppressWarnings("unchecked")
        Map<String, String> map = getStaticPrivateInternalMapLocalePrefix();

        String localPrefix = null;

        // find the language_Country value matching the internal excel
        // prefix.
        for (Map.Entry<String, String> entry : map.entrySet()) {

            LOGGER.info("value : " + entry.getValue() + ", key :"
                    + entry.getKey());

            if (entry.getValue().equals(prefixes)
                    && !StringUtils.isBlank(entry.getKey())) {
                localPrefix = entry.getKey();
                break;
            }
        }

        // Generate a Locale with language, uppercase(country) info.
        LOGGER.info(localPrefix);
        if (localPrefix.indexOf('_') > 0) {
            String[] languageCountry = localPrefix.split("_");
            return new Locale(languageCountry[0],
                    StringUtils.defaultString(languageCountry[1]
                            .toUpperCase()));
        }

        // nothing found.
        return null;

        // factorized the multiples exceptions.
    } catch (Exception e) {
        throw new UnsupportedOperationException(e);
    }

}

/**
 * gets the internal code map for locale used by Excel.
 * 
 * @return the internal map.
 * @throws NoSuchFieldException
 *             if the private field name changes.
 * @throws IllegalAccessException
 *             if the accessible is restricted.
 */
private static Map<String, String> getStaticPrivateInternalMapLocalePrefix()
        throws NoSuchFieldException, IllegalAccessException {
    // REFLECTION
    Class<?> clazz = DateFormatConverter.class;
    Field fieldlocalPrefixes = (Field) clazz
            .getDeclaredField(DATE_CONVERTER_PRIVATE_PREFIXES_MAP);

    // change from private to public.
    fieldlocalPrefixes.setAccessible(true);

    @SuppressWarnings("unchecked")
    Map<String, String> map = (Map<String, String>) fieldlocalPrefixes
            .get(clazz);

    LOGGER.info("MAP localPrefixes : " + map);
    return map;
}
    ....
    final CellStyle cellStyle = reopenedCell.getCellStyle();

    Locale locale = extractLocaleFromDateCellStyle(cellStyle);
    LOGGER.info("FOUND LOCAL : " + locale);

    // use the same local from the cell style during writing.
    DataFormatter df = new DataFormatter(locale);

    String reOpenValue = df.formatCellValue(reopenedCell);