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