获取单元格值,以及它在excel中的显示方式

我目前正在开发一个使用Apache POI读取excel文件的项目。

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

9,000.00

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

我发现一些post告诉使用DataFormat类,但根据我的理解,它需要您的代码知道该单元格具有的格式。 在我的情况下,我不知道单元格可能具有的格式。

那么,我如何检索单元格值如何在excel中呈现?

Excel将一些单元格存储为字符串,但大多数作为具有特殊格式规则的数字应用于它们。 你需要做的是对数字单元格运行那些格式化规则,以生成看起来像在Excel中的字符串。

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

你需要做的就是:

  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的单元格样式的dateConverted格式(来自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 * DateFormatConverter.localePrefixes private static field. * 

* 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 map = getStaticPrivateInternalMapLocalePrefix(); String localPrefix = null; // find the language_Country value matching the internal excel // prefix. for (Map.Entry 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 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 map = (Map) fieldlocalPrefixes .get(clazz); LOGGER.info("MAP localPrefixes : " + map); return map; }

因此,以下简单的代码应该可以解决问题。 请注意,代码未针对空值进行完全测试,并且取决于您使用的POI版本,直到他们更改了LOCALE OBSERVER MADNESS 🙂

  .... 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); 

问候。

使用CellType可以检查每件事

 if (cellValue.getCellType() == Cell.CELL_TYPE_NUMERIC) 

// cellValue是Numeric

 if (cellValue.getCellType() == Cell.CELL_TYPE_STRING) 

// cellValue是一个String

date也以数字forms给出,那时使用dateUtil检查给定单元格是否为date

 if (DateUtil.isCellDateFormatted(cellData)) 

之后,您可以将cellvalue转换为日期