157
  1. 我有这样内容的excel文件:

    • A1:一些字符串

    • A2:2

    所有字段都设置为字符串格式。

  2. 当我使用 POI 在 java 中读取文件时,它告诉 A2 是数字单元格格式。

  3. 问题是 A2 中的值可以是 2 或 2.0 (我希望能够区分它们)所以我不能只使用.toString().

我该怎么做才能将值读取为字符串?

4

21 回答 21

345

我有同样的问题。我cell.setCellType(Cell.CELL_TYPE_STRING);在读取字符串值之前做过,无论用户如何格式化单元格,它都解决了这个问题。

于 2010-08-17T15:54:17.963 回答
113

当你问这个问题时,我不认为我们有这堂课,但今天有一个简单的答案。

您要做的是使用DataFormatter 类。您将此单元格传递给它,它会尽力返回一个字符串,其中包含 Excel 会为您显示该单元格的内容。如果你给它传递一个字符串单元格,你会得到这个字符串。如果您传递一个应用了格式规则的数字单元格,它将根据它们格式化数字并返回字符串。

对于您的情况,我假设数字单元格应用了整数格式规则。如果您要求 DataFormatter 格式化这些单元格,它会返回一个包含整数字符串的字符串。

另外,请注意很多人建议这样做cell.setCellType(Cell.CELL_TYPE_STRING),但Apache POI JavaDocs 非常明确地声明您不应该这样做!进行setCellType调用将丢失格式,因为javadocs 解释了转换为保留格式的字符串的唯一方法是使用DataFormatter 类

使用此类的一个简单示例:

DataFormatter dataFormatter = new DataFormatter();
String formattedCellStr = dataFormatter.formatCellValue(cell);
于 2011-08-17T23:26:25.190 回答
63

以下代码适用于任何类型的单元格。

InputStream inp =getClass().getResourceAsStream("filename.xls"));
Workbook wb = WorkbookFactory.create(inp);
DataFormatter objDefaultFormat = new DataFormatter();
FormulaEvaluator objFormulaEvaluator = new HSSFFormulaEvaluator((HSSFWorkbook) wb);

Sheet sheet= wb.getSheetAt(0);
Iterator<Row> objIterator = sheet.rowIterator();

while(objIterator.hasNext()){

    Row row = objIterator.next();
    Cell cellValue = row.getCell(0);
    objFormulaEvaluator.evaluate(cellValue); // This will evaluate the cell, And any type of cell will return string value
    String cellValueStr = objDefaultFormat.formatCellValue(cellValue,objFormulaEvaluator);

}
于 2014-07-02T14:37:46.960 回答
41

当不希望修改单元格的类型时,我会推荐以下方法:

if(cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
    String str = NumberToTextConverter.toText(cell.getNumericCellValue())
}

NumberToTextConverter 可以使用 Excel 的规则正确地将双精度值转换为文本,而不会损失精度。

于 2015-12-24T14:29:13.957 回答
19

正如 Poi 的 JavaDocs ( https://poi.apache.org/apidocs/org/apache/poi/ss/usermodel/Cell.html#setCellType%28int%29 ) 中已经提到的,不要使用:

cell.setCellType(Cell.CELL_TYPE_STRING);

但使用:

DataFormatter df = new DataFormatter();
String value = df.formatCellValue(cell);

http://massapi.com/class/da/DataFormatter.html上的更多示例

于 2016-11-11T14:57:36.717 回答
14

是的,这非常有效

受到推崇的:

        DataFormatter dataFormatter = new DataFormatter();
        String value = dataFormatter.formatCellValue(cell);

老的:

cell.setCellType(Cell.CELL_TYPE_STRING);

即使您在从cell公式中检索值时遇到问题,这仍然有效。

于 2013-10-07T04:03:01.893 回答
4

尝试:

new java.text.DecimalFormat("0").format( cell.getNumericCellValue() )

应该正确格式化数字。

于 2011-08-17T13:55:21.160 回答
1

只要在用户输入数字之前单元格是文本格式,POI 就会允许您以字符串的形式获取值。一个关键是,如果单元格的左上角有一个小绿色三角形,格式为文本,您将能够将其值作为字符串检索(只要看起来是数字,就会出现绿色三角形被强制转换成文本格式)。如果您有包含数字的文本格式单元格,但 POI 不允许您将这些值作为字符串获取,您可以对电子表格数据执行一些操作以允许这样做:

  • 双击单元格,使编辑光标出现在单元格内,然后单击 Enter(一次只能执行一个单元格)。
  • 使用 Excel 2007 文本转换功能(可以同时在多个单元格上完成)。
  • 将有问题的值剪切到另一个位置,将电子表格单元格重新格式化为文本,然后将先前剪切的值作为未格式化的值重新粘贴到适当的区域。

您可以做的最后一件事是,如果您使用 POI 从 Excel 2007 电子表格中获取数据,您可以使用 Cell 类的“getRawValue()”方法。这不关心格式是什么。它只会返回一个带有原始数据的字符串。

于 2012-01-12T20:12:07.760 回答
0

当我们使用 Apache POI 库读取 MS Excel 的数字单元格值时,它会将其读取为数字。但有时我们希望它读取为字符串(例如电话号码等)。我是这样做的:

  1. 插入一个新列,第一个单元格 =CONCATENATE("!",D2)。我假设 D2 是您的电话号码列的单元格 ID。将新单元格拖到最后。

  2. 现在,如果您使用 POI 读取单元格,它将读取公式而不是计算值。现在执行以下操作:

  3. 添加另一列

  4. 选择在步骤 1 中创建的完整列。然后选择 Edit->COPY

  5. 转到在步骤 3 中创建的列的顶部单元格。然后选择 Edit->Paste Special

  6. 在打开的窗口中,选择“值”单选按钮

  7. 选择“确定”

  8. 现在使用 POI API 阅读……在 Java 中阅读之后……只需删除第一个字符,即“!”

于 2010-12-12T18:05:00.383 回答
0

我在包含数千个数字的数据集上也遇到过类似的问题,我认为我找到了一种简单的解决方法。我需要在数字之前插入撇号,以便单独的数据库导入始终将数字视为文本。在此之前,数字 8 将作为 8.0 导入。

解决方案:

  • 保持所有格式为常规。
  • 在这里,我假设数字存储在从第 1 行开始的 A 列中。
  • 将 ' 放入 B 列并根据需要复制尽可能多的行。工作表中不显示任何内容,但单击单元格,您可以在公式栏中看到撇号。
  • 在 C 列中:=B1&A1。
  • 选择 C ​​列中的所有单元格,然后使用“值”选项将选择性粘贴到 D 列。

嘿 Presto 所有数字,但存储为文本。

于 2011-09-06T09:52:24.497 回答
0

如果单元格类型是数字,getStringCellValue 返回 NumberFormatException。如果您不想将单元格类型更改为字符串,则可以这样做。

String rsdata = "";
try {
    rsdata = cell.getStringValue();
} catch (NumberFormatException ex) {
    rsdata = cell.getNumericValue() + "";
}
于 2014-08-13T03:19:15.823 回答
0

其中许多答案都引用了旧的 POI 文档和类。在最新的 POI 3.16 中,不推荐使用int 类型的 Cell

Cell.CELL_TYPE_STRING

在此处输入图像描述

相反,可以使用CellType 枚举。

CellType.STRING 

只需确保使用 poi 依赖项以及 poi-ooxml 依赖项将您的 pom 更新到新的 3.16 版本,否则您将继续遇到异常。此版本的一个优点是您可以在创建单元格时指定单元格类型,从而消除先前答案中描述的所有额外步骤:

titleRowCell = currentReportRow.createCell(currentReportColumnIndex, CellType.STRING);
于 2017-06-09T16:36:57.910 回答
0

这对我来说很完美。

Double legacyRow = row.getCell(col).getNumericCellValue();
String legacyRowStr = legacyRow.toString();
if(legacyRowStr.contains(".0")){
    legacyRowStr = legacyRowStr.substring(0, legacyRowStr.length()-2);
}
于 2017-10-03T10:17:36.650 回答
0

我更愿意走 wil 的答案或 Vinayak Dornala 的路线,不幸的是,它们对我的表现影响很大。我寻求隐式转换的HACKY解决方案:

for (Row row : sheet){
String strValue = (row.getCell(numericColumn)+""); // hack
...

我不建议你这样做,因为我的情况是因为系统的工作原理和我有一个可靠的文件来源。

脚注: numericColumn 是一个 int,它是通过读取已处理文件的标题生成的。

于 2018-05-29T10:14:00.760 回答
0
public class Excellib {
public String getExceldata(String sheetname,int rownum,int cellnum, boolean isString) {
    String retVal=null;
    try {
        FileInputStream fis=new FileInputStream("E:\\Sample-Automation-Workspace\\SampleTestDataDriven\\Registration.xlsx");
        Workbook wb=WorkbookFactory.create(fis);
        Sheet s=wb.getSheet(sheetname);
        Row r=s.getRow(rownum);
        Cell c=r.getCell(cellnum);
        if(c.getCellType() == Cell.CELL_TYPE_STRING)
        retVal=c.getStringCellValue();
        else {
            retVal = String.valueOf(c.getNumericCellValue());
        }

我试过这个,它对我有用

于 2018-10-23T09:46:42.097 回答
0

有一个现成的包装器(可以应用一些额外的优化)

  • 它支持数字和字符串单元格

  • 自动识别和处理公式

  • 避免一些样板

     public final class Cell {
    
     private final static DataFormatter FORMATTER = new DataFormatter();
    
     private XSSFCell mCell;
    
     public Cell(@NotNull XSSFCell cell) {
         mCell = cell;
    
         if (isFormula()) {
             XSSFWorkbook book = mCell.getSheet().getWorkbook();
             FormulaEvaluator evaluator = book.getCreationHelper().createFormulaEvaluator();
             mCell = (XSSFCell) evaluator.evaluateInCell(mCell);
         }
     }
    
     /**
      * Get content
      */
     public final int getInt() {
         return (int) getLong();
     }
    
     public final long getLong() {
         return Math.round(getDouble());
     }
    
     public final double getDouble() {
         return mCell.getNumericCellValue();
     }
    
     public final String getString() {
         if (!isString()) {
             return FORMATTER.formatCellValue(mCell);
         }
         return mCell.getStringCellValue();
     }
    
     /**
      * Get properties
      */
     public final boolean isNumber() {
         if (isFormula()) {
             return mCell.getCachedFormulaResultType().equals(CellType.NUMERIC);
         }
         return mCell.getCellType().equals(CellType.NUMERIC);
     }
    
     public final boolean isString() {
         if (isFormula()) {
             return mCell.getCachedFormulaResultType().equals(CellType.STRING);
         }
         return mCell.getCellType().equals(CellType.STRING);
     }
    
     public final boolean isFormula() {
         return mCell.getCellType().equals(CellType.FORMULA);
     }
    
     /**
      * Debug info
      */
     @Override
     public String toString() {
         return getString();
     }
     }
    
于 2020-11-30T23:06:35.580 回答
-1

无论如何,您是否控制 Excel 工作表?是否有用户提供输入的模板?如果是这样,您可以为您设置输入单元格的代码格式。

于 2009-12-02T00:12:48.380 回答
-1

看起来这在当前版本的 POI 中无法完成,基于这个错误的事实:

https://issues.apache.org/bugzilla/show_bug.cgi?id=46136

仍然很优秀。

于 2010-09-24T18:29:10.700 回答
-2

我们遇到了同样的问题,并强制我们的用户在输入值之前将单元格格式化为“文本” 。这样,Excel 就可以正确地将偶数存储为文本。如果随后更改格式,Excel 只会更改值的显示方式,但不会更改值的存储方式,除非再次输入值(例如,在单元格中按回车键)。

如果 Excel 认为单元格包含数字但格式为文本,则 Excel 是否将值正确存储为文本由 Excel 显示在单元格左上角的绿色小三角形指示。

于 2009-07-30T10:24:41.863 回答
-2

cell.setCellType(Cell.CELL_TYPE_STRING); 对我来说很好

于 2015-05-23T20:43:20.530 回答
-4

强制转换为 int 然后执行.toString(). 它很丑,但它有效。

于 2009-07-27T20:08:11.703 回答