poi读取xlsx中CELL_TYPE_FORMULA值

本文探讨了在处理Excel中使用公式计算的单元格数据时遇到的数值异常问题,介绍了通过添加额外列存储计算结果并读取该列的方法来解决此问题。同时,提出了解决方案为避免数值精度损失,以及提供了将文件转换为xls格式作为备选方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其他的就不错说了,网上很多。

碰到读取公式类型的单元格读不出来,试了HXSSFWorkbook也读不出来,后来试了下XSSFCell.getCTCell().getV() 就读出来了。

但有个问题就是XSSFCell.getCTCell().getV() 是重新计算一遍的,如果单元格的值是另外几个单元格的复数值计算的,单元值可能会出现111.000000000001 (111.0) 111.199999999999(111.2)这种数的。

解决可以:再添加一列值等于公式列,读取新列就行了;实在不想的话就转回xls文件读取。

如有更好的方法希望提供一下微笑


<think>我们正在讨论的是Apache POI库中`setCellType`方法被弃用的问题。根据引用[1][2][3],在较新的POI版本中(如4.1.2),`setCellType(Cell.CELL_TYPE_STRING)`已经被标记为过时,推荐使用新的方式来处理单元格类型。 ### 问题原因 在旧版POI中,我们通常这样设置单元格类型为字符串: ```java cell.setCellType(Cell.CELL_TYPE_STRING); // 已过时 ``` 但在新版本中(POI 3.15及以上),该方法已被弃用,因为POI引入了新的枚举`CellType`,并且改变了单元格类型处理的策略。直接设置单元格类型可能会导致一些副作用,比如丢失原始数据。 ### 解决方案 根据引用[2][3],推荐使用`DataFormatter`来获取单元格的,它会根据单元格的类型自动格式化为字符串,而不需要显式设置单元格类型。 #### 方法1:使用DataFormatter(推荐) ```java import org.apache.poi.ss.usermodel.DataFormatter; // 在读取单元格时 DataFormatter formatter = new DataFormatter(); String cellValue = formatter.formatCellValue(cell); // 无论单元格是什么类型,都返回格式化的字符串 ``` 这种方法的好处是: 1. 不需要改变单元格的原始类型。 2. 自动处理数字、日期等格式。 3. 避免因设置单元格类型而可能引发的异常。 #### 方法2:使用新的枚举(不推荐直接设置类型) 如果确实需要设置单元格类型(比如在写入时),可以使用新的枚举`CellType`: ```java cell.setCellType(CellType.STRING); // 注意:这个方法在POI 5.0+中已被移除 ``` 但是,根据引用[2],即使使用`CellType`枚举,`setCellType`方法也被标记为`@Deprecated`,并且在POI 5.0+中会被移除。因此,在写入时,更好的做法是直接设置单元格的类型,而不是改变其类型。 例如,写入字符串应该直接使用: ```java cell.setCellValue("你的字符串"); // 这样POI会自动将单元格设置为字符串类型 ``` ### 注意事项 1. **读取时**:优先使用`DataFormatter`来获取字符串,避免设置单元格类型。 2. **写入时**:直接调用相应的`setCellValue`方法,POI会根据自动设置单元格类型。 3. **避免使用弃用方法**:不要使用`setCellType`,因为它在新版本中已被移除。 ### 示例代码 读取Excel文件中的单元格(使用DataFormatter): ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ReadExcelExample { public static void main(String[] args) throws Exception { Workbook workbook = new XSSFWorkbook("example.xlsx"); Sheet sheet = workbook.getSheetAt(0); DataFormatter formatter = new DataFormatter(); for (Row row : sheet) { for (Cell cell : row) { // 使用DataFormatter获取单元格的字符串表示 String cellValue = formatter.formatCellValue(cell); System.out.print(cellValue + "\t"); } System.out.println(); } workbook.close(); } } ``` 写入Excel文件(不需要设置单元格类型): ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class WriteExcelExample { public static void main(String[] args) throws Exception { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); Row row = sheet.createRow(0); Cell cell = row.createCell(0); cell.setCellValue("字符串"); // 自动设置为字符串类型 // 保存文件 try (FileOutputStream out = new FileOutputStream("output.xlsx")) { workbook.write(out); } workbook.close(); } } ``` ### 总结 - **读取单元格**:使用`DataFormatter.formatCellValue(cell)`,无需设置单元格类型。 - **写入单元格**:直接使用`setCellValue`方法,POI会自动处理类型。 这样,你的代码将兼容新版本的POI(如4.1.2),并避免使用已弃用的方法。 ### 相关问题 1. 如何使用Apache POI读取Excel中的日期单元格? 2.POI中如何设置单元格的样式(如字体、颜色)? 3. 使用POI处理大文件时如何避免内存溢出?</think>### Apache POI 新版本中替换 `setCellType(Cell.CELL_TYPE_STRING)` 的解决方案 在 Apache POI 4.x+ 版本中,`setCellType()` 方法已被弃用并最终移除。以下是三种替代方案,按推荐程度排序: #### ✅ 最佳方案:使用 DataFormatter (推荐) ```java import org.apache.poi.ss.usermodel.DataFormatter; // 创建格式化器 DataFormatter formatter = new DataFormatter(); // 获取单元格(自动处理所有类型) String cellValue = formatter.formatCellValue(cell); ``` **优点**: 1. 自动处理数字、日期、公式等所有数据类型 2. 保留原始数据格式(如货币符号、百分比) 3. 无需预先知道单元格类型[^2][^3] #### ⚠️ 过渡方案:使用新枚举(仅限 POI 3.17-4.x) ```java // POI 3.17 引入的新枚举(5.0+ 已移除) cell.setCellType(CellType.STRING); // 仍会被标记为过时 // 然后获取 String value = cell.getStringCellValue(); ``` **注意**:此方法在 POI 5.0+ 中**完全移除**,不推荐使用[^2][^4] #### 🧩 类型安全方案:直接按类型读取 ```java switch (cell.getCellType()) { case STRING: value = cell.getStringCellValue(); break; case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { value = cell.getDateCellValue().toString(); } else { value = String.valueOf(cell.getNumericCellValue()); } break; case BOOLEAN: value = String.valueOf(cell.getBooleanCellValue()); break; case FORMULA: value = cell.getCellFormula(); break; default: value = ""; } ``` ### 📌 关键变更说明 | POI 版本 | 状态 | 替代方案 | |---------|------|---------| | ≤ 3.16 | 正常 | `setCellType(Cell.CELL_TYPE_STRING)` | | 3.17-4.x | 过时 | `setCellType(CellType.STRING)` | | ≥ 5.0 | 移除 | **必须使用 DataFormatter** | ### 💡 实际应用场景 1. **读取混合类型列**(数字/文本共存) ```java DataFormatter formatter = new DataFormatter(); for (Row row : sheet) { String id = formatter.formatCellValue(row.getCell(0)); // 自动转换 String name = formatter.formatCellValue(row.getCell(1)); } ``` 2. **导出数据保持格式** ```java // 不需要设置单元格类型! cell.setCellValue("123456"); // POI 自动识别为字符串 ``` ### ⚠️ 常见错误解决 **报错:** `Cannot get a STRING value from a NUMERIC cell` **原因:** 未处理数字单元格直接调用 `getStringCellValue()` **修复:** ```java // 错误做法 ❌ cell.setCellType(CellType.STRING); String val = cell.getStringCellValue(); // 正确做法 ✅ String val = new DataFormatter().formatCellValue(cell); ``` ### 总结建议 1. 优先使用 **DataFormatter** 处理所有读取操作 2. 写入时无需设置类型,直接 `setCellValue()` 即可 3. 检查 POI 版本: ```xml <!-- pom.xml 推荐配置 --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>5.2.3</version> <!-- 2023最新版 --> </dependency> ``` > 📌 **迁移提示**:旧项目升级时,全局搜索替换 `setCellType(Cell.` 为 `// 已废弃:`,并改用 DataFormatter 实现[^1][^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值