新版POI如何获取日期类型的cell的值

本文介绍使用Apache POI处理Excel文件中日期格式的具体方法。针对不同格式的日期单元格,提供了一种实用的解决方案,确保能正确转换并输出日期。

使用POI读取Excel值的同学,一定为日期类型抓狂过!

POI对单元格日期处理很弱,没有针对的类型,日期类型取出来的也是一个double值,所以同样作为数值类型。即使使用cell.setCellType(CellType.STRING) 也还是会返回一个数字

 

网上大部分的方法是:
cell.getCellType()
但是在新版的POI中,比如3.15版,这个写法已经被放弃使用了。由于项目需要在下不能调整jar包,只好硬着头皮去解决。

 

后来发现了一个方法:
cell.getCellStyle().getDataFormatString() 可以判断单元格的格式类型,如下图


于是便可以使用如下方法判断:

if("yyyy/mm;@".equals(cell.getCellStyle().getDataFormatString()) || "m/d/yy".equals(cell.getCellStyle().getDataFormatString())
        || "yy/m/d".equals(cell.getCellStyle().getDataFormatString()) || "mm/dd/yy".equals(cell.getCellStyle().getDataFormatString())
        || "dd-mmm-yy".equals(cell.getCellStyle().getDataFormatString())|| "yyyy/m/d".equals(cell.getCellStyle().getDataFormatString())){
    return new SimpleDateFormat("yyyy/MM/dd").format(cell.getDateCellValue());
}

使用这个方法判断的格式有限,如果能够限定单元格格式的话,这样是足够解决的。

 

但我的项目坑爹的是Excel中的日期格式也是不固定的,还需要另谋出路。
在调试的时候发现,明明就显示着这个cell的值,是个日期。

如上图,这个日期【31-一月-2005】并不在这个cell下的某一个子元素里,至少我找了很久是没找到。只能使用cell.toString() 得到

最后我的解决办法是:首先使用了cell.getCellStyle().getDataFormatString()判断,如果能得到就返回“yyyy/MM/dd”格式的日期。如果得不到,最后都返回cell.toString()。这样至少不会返回一个数字了,也不知道对其他类型的单元格有没有影响,目前跑了几张表没有报错

 

这种解决办法当然是不好的,肯定是有一种好的方法我没找到,如果哪位大侠找到了,烦请告知一声,在下拜谢了!

 


 

到最后果然还是找我麻烦了,【31-一月-2005】格式不行,必须转成“yyyy/MM/dd”格式。

然后想,要不写个正则表达式,通过判断字符串的方式,来判断出这种日期类型。坑爹了,正则不会写。。。。。。。明明感觉很简单的,就是不对

再然后,耍小聪明,改成通过使用java中的字符串分割一点点判断,先放代码:

 1   /**
 2      * 分多种格式解析单元格的值
 3      *
 4      * @param cell  单元格
 5      * @return  单元格的值
 6      */
 7     public static String convertCellToString(Cell cell){
 8         //如果为null会抛出异常,应当返回空字符串
 9         if (cell == null)
10             return "";
11 
12         //POI对单元格日期处理很弱,没有针对的类型,日期类型取出来的也是一个double值,所以同样作为数值类型
13         //解决日期2006/11/02格式读入后出错的问题,POI读取后变成“02-十一月-2006”格式
14         if(cell.toString().contains("-") && checkDate(cell.toString())){
15             String ans = "";
16             try {
17                 ans = new SimpleDateFormat("yyyy/MM/dd").format(cell.getDateCellValue());
18             } catch (Exception e) {
19                 ans = cell.toString();
20             }
21             return ans;
22         }
23 
24         cell.setCellType(CellType.STRING);
25         return cell.getStringCellValue();
26     }
27 
28     /**
29      * 判断是否是“02-十一月-2006”格式的日期类型
30      */
31     private static boolean checkDate(String str){
32         String[] dataArr =str.split("-");
33         try {
34             if(dataArr.length == 3){
35                 int x = Integer.parseInt(dataArr[0]);
36                 String y =  dataArr[1];
37                 int z = Integer.parseInt(dataArr[2]);
38                 if(x>0 && x<32 && z>0 && z< 10000 && y.endsWith("月")){
39                     return true;
40                 }
41             }
42         } catch (Exception e) {
43             return false;
44         }
45         return false;
46     }

同学们慢慢理解吧,代码虽然挫了一点,也不能保证完全正确,但至少这种情况下是可以使用的。

 

原创文章,欢迎转载,转载请注明出处!

 

转载于:https://www.cnblogs.com/acm-bingzi/p/6674834.html

<think>嗯,用户问的是如何将POI中所有单元格的转换为字符串。首先,我需要明确POI指的是什么。通常,POI是Apache POI库,用于处理Microsoft Office文档,尤其是Excel文件。所以用户可能是在使用Apache POI时遇到了单元格格式的问题,希望将所有单元格的数据转为字符串类型,避免数字或日期被错误处理。 接下来,用户提到的“任何cell都转换为string”,可能需要考虑不同的单元格类型,比如数日期、布尔、公式等。处理这些类型时,需要分别处理,确保无论原来的格式是什么,最终都以字符串形式读。 首先,我应该回忆Apache POI中如何读单元格数据。通常,使用Cell接口的getCellType()方法来判断类型,然后调用相应的方法,如getNumericCellValue()、getStringCellValue()等。但用户的需求是将所有类型转为字符串,所以可能需要针对每种类型进行处理,将结果转为字符串。 比如,对于数字类型,直接再转为字符串可能会有科学计数法的问题,或者小数点后的零被省略,可能需要使用DataFormatter类。DataFormatter可以按照单元格的格式规则将格式化为字符串,保持和Excel中显示的一致。这可能是更好的方法,因为直接转换可能不符合用户的预期。 另外,公式单元格(FORMULA)需要注意,可能需要先判断公式的结果类型,再进行处理。或者使用DataFormatter来处理,因为它会自动计算公式结果并格式化。 此外,用户可能希望避免数字被当作数类型处理,比如长数字(如身份证号)在Excel中显示为科学计数法,读时丢失精度。这时,将单元格设置为字符串格式,或者在读时强制转换为字符串是关键。 可能的解决方案有两种:一是在读时使用DataFormatter处理所有单元格;二是在写入时设置单元格格式为文本,但这决于用户的具体场景是读还是写。 现在需要整理步骤,给出示例代码。比如,使用DataFormatter来处理读,或者遍历每个单元格,根据类型转换。同时提醒用户关于公式单元格的处理,或者设置单元格类型为STRING的方法可能存在的问题,比如已经存在的数单元格可能需要先更改类型。 另外,需要注意不同版本的POI中,CellType的枚举可能有变化,比如旧版本用的是Cell.CELL_TYPE_STRING,而新版本是CellType.STRING,需要提醒用户根据版本调整代码。 可能的示例代码结构: 1. 使用DataFormatter: DataFormatter formatter = new DataFormatter(); String value = formatter.formatCellValue(cell); 这种方法简单,且处理了公式和格式问题。 2. 手动处理每个类型: switch (cell.getCellType()) { case STRING: ... case NUMERIC: ... case BOOLEAN: ... case FORMULA: ... default: ... } 但这种方法更繁琐,且可能不如DataFormatter准确。 因此,推荐使用DataFormatter的方法,因为它更简洁且处理了各种格式和公式结果。 最后,可能需要提醒用户,如果是在生成Excel文件时希望所有单元格为字符串,需要在创建单元格时设置格式为文本,或者使用setCellValue时传入字符串,并预先设置单元格类型为STRING,避免Excel自动转换。 总结回答的结构:介绍POI,问题背景,两种方法(DataFormatter和手动处理),示例代码,注意事项(版本差异,写入时的处理)。</think>在Apache POI(用于操作Excel等文档的Java库)中,若需将所有单元格(Cell)的强制转换为字符串类型,通常是为了避免数日期等类型被自动解析。以下是实现方法和注意事项: --- ### **方法一:使用 `DataFormatter`** 这是**推荐方案**,能保留单元格的显示格式(如日期格式、货币符号等),且自动处理公式结果。 ```java import org.apache.poi.ss.usermodel.*; public class CellToStringExample { public static void main(String[] args) { Workbook workbook = new XSSFWorkbook(); // 或 HSSFWorkbook Sheet sheet = workbook.createSheet("Sheet1"); // 示例:创建一个包含数字和日期的单元格 Row row = sheet.createRow(0); Cell numericCell = row.createCell(0); numericCell.setCellValue(12345.6789); Cell dateCell = row.createCell(1); dateCell.setCellValue(new Date()); // 使用 DataFormatter 转换所有单元格为字符串 DataFormatter formatter = new DataFormatter(); for (Row r : sheet) { for (Cell cell : r) { String strValue = formatter.formatCellValue(cell); System.out.println("单元格(字符串): " + strValue); } } } } ``` --- ### **方法二:手动处理单元格类型** 若需完全控制转换逻辑,可遍历单元格类型并处理: ```java public static String getCellAsString(Cell cell) { if (cell == null) return ""; switch (cell.getCellType()) { case STRING: return cell.getStringCellValue(); case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { return cell.getDateCellValue().toString(); // 日期转为字符串 } else { return String.valueOf(cell.getNumericCellValue()); // 数转为字符串 } case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); case FORMULA: // 处理公式结果 return cell.getCellFormula() + "=" + evaluateFormula(cell); case BLANK: return ""; default: return "未知类型"; } } private static String evaluateFormula(Cell cell) { FormulaEvaluator evaluator = cell.getSheet().getWorkbook() .getCreationHelper().createFormulaEvaluator(); CellValue cellValue = evaluator.evaluate(cell); switch (cellValue.getCellType()) { case NUMERIC: return String.valueOf(cellValue.getNumberValue()); case STRING: return cellValue.getStringValue(); default: return "公式结果未知"; } } ``` --- ### **注意事项** 1. **科学计数法问题** 长数字(如身份证号)在Excel中可能显示为科学计数法,直接读会丢失精度。 **解决方案**:在写入时设置单元格格式为文本: ```java Cell cell = row.createCell(0); cell.setCellType(CellType.STRING); // 强制设置为文本类型 cell.setCellValue("123456789012345678"); ``` 2. **POI版本差异** - 旧版本(如3.x):使用 `Cell.CELL_TYPE_STRING` - 新版本(4.x+):使用 `CellType.STRING` 3. **性能优化** 若处理大型文件,建议使用 `Streaming API`(如 `SXSSFWorkbook`)避免内存溢出。 --- ### **应用场景** - 读Excel时保留原始格式(如电话号码、身份证号)。 - 导出数据到文本文件或数据库时统一类型。 - 避免数精度丢失或日期解析错误。 根据需求选择 `DataFormatter`(推荐)或手动处理逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值