【问题标题】:JAVA Apache POI Custom FormatJAVA Apache POI 自定义格式
【发布时间】:2016-03-16 10:37:03
【问题描述】:

我正在使用 poi 版本:3.14

我访问一个 Excel (.xlsx) 文件

this.workbook = WorkbookFactory.create(new FileInputStream(f.getPath()));
this.workbook.setMissingCellPolicy(Row.CREATE_NULL_AS_BLANK);
this.sheet = workbook.getSheetAt(0);

这是在应用于单元格的 .xlsx 文件中找到的自定义格式。我想在我的代码中显示单元格值。

如您所见,文件中可见的单元格值为“031642153283700100”。此外,当我单击此特定单元格时,值将更改为“42153283700100”(未应用自定义格式的数据)。

编辑

原始单元格类型是 CELL_TYPE_NUMERIC。

==>


如何在 java 代码中显示格式化值“031642153283700100”?

我试过了:

  • cell.toString() => "42153283700100"
  • cell.getNumericCellValue() => "42153283700100"

与之前的单元格类型转换:

cell.setCellType(Cell.CELL_TYPE_STRING);
  • cell.getStringCellValue() => "42153283700100"
  • cell.getRichStringCellValue() => "42153283700100"

  • 带有 formatCellValue(cell) 方法的旧 HSSFDataFormatter => "421532837001000316"

【问题讨论】:

    标签: java excel apache-poi xssf


    【解决方案1】:

    对于数字格式,您应该使用CellGeneralFormatterCellNumberFormatter

    例子:

    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    
    import org.apache.poi.ss.format.*;
    
    import java.io.IOException;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.io.FileInputStream;
    
    class ReadExcelWithFormats {
    
     public static void main(String[] args) {
      try {
    
       InputStream inp = new FileInputStream("workbook.xlsx");
       Workbook wb = WorkbookFactory.create(inp);
    
       Sheet sheet = wb.getSheetAt(0);
    
       for (Row row : sheet) {
    
        for (Cell cell : row) {
    
         String formatstring = cell.getCellStyle().getDataFormatString();
         System.out.println(formatstring);
    
         switch (cell.getCellType()) {
    
          //...
    
          case Cell.CELL_TYPE_NUMERIC:
           double cellvalue = cell.getNumericCellValue();
    
           System.out.println(cellvalue);
    
           String formattedvalue = "";
    
           if ("general".equals(formatstring.toLowerCase())) {
            formattedvalue = new CellGeneralFormatter().format(cellvalue);
           } else {
            formattedvalue = new CellNumberFormatter(formatstring).format(cellvalue);
           }
    
           System.out.println(formattedvalue);
    
          break;
    
          //...
    
          default:
           System.out.println();
         }
        }
       }
    
      } catch (InvalidFormatException ifex) {
      } catch (FileNotFoundException fnfex) {
      } catch (IOException ioex) {
      }
     }
    }
    

    编辑

    好的,让我们举一个更一般的例子。以上不适用于日期(我已经知道),但也不适用于所有数字格式。后者我认为CellNumberFormatter 应该这样做,但事实并非如此。不幸的是,它甚至会产生一些正确的数字格式的错误。

    Excel 中,数字格式最多可以包含 4 个以分号分隔的部分。第一部分是大于0的数字,第二部分是小于0的数字,第三部分是等于0的数字,第四部分是文本。

    format > 0;format < 0;format = 0;text

    由于CellNumberFormatter 不能正确处理这个问题,我们应该在使用CellNumberFormatter 之前进行处理。

    import org.apache.poi.ss.usermodel.*;
    import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
    
    import org.apache.poi.ss.format.*;
    
    import java.io.IOException;
    import java.io.FileNotFoundException;
    import java.io.InputStream;
    import java.io.FileInputStream;
    
    import java.util.Date;
    
    class ReadExcelWithFormats {
    
     public static void main(String[] args) {
      try {
    
       InputStream inp = new FileInputStream("workbook.xlsx");
       Workbook wb = WorkbookFactory.create(inp);
    
       Sheet sheet = wb.getSheetAt(0);
    
       for (Row row : sheet) {
    
        for (Cell cell : row) {
    
         String formatstring = cell.getCellStyle().getDataFormatString();
         System.out.println(formatstring);
    
         switch (cell.getCellType()) {
    
          //...
    
          case Cell.CELL_TYPE_NUMERIC:
    
           String formattedvalue = "";
           String[] formatstringparts = formatstring.split(";");
    
           if (DateUtil.isCellDateFormatted(cell)) {
    
            Date date = cell.getDateCellValue();
            System.out.println(date);
    
            String dateformatstring = "";
            if (cell.getCellStyle().getDataFormat() == 14) { //default short date without explicit formatting
             dateformatstring = "yyyy-MM-dd"; //default date format for this
            } else if (cell.getCellStyle().getDataFormat() == 22) { //default short datetime without explicit formatting
             dateformatstring = "yyyy-MM-dd hh:mm"; //default datetime format for this
            } else { //other data formats with explicit formatting
             dateformatstring = formatstringparts[0];
            }
            formattedvalue = new CellDateFormatter(dateformatstring).format(date);
           } else {
    
            double cellvalue = cell.getNumericCellValue();
            System.out.println(cellvalue);
    
            switch (formatstringparts.length) {
             case 4:
             case 3:
              if (cellvalue > 0) {
               if ("general".equals(formatstringparts[0].toLowerCase())) {
                formattedvalue = new CellGeneralFormatter().format(cellvalue);
               } else {
                formattedvalue = new CellNumberFormatter(formatstringparts[0]).format(cellvalue);
               }
              }
              if (cellvalue < 0) {
               if ("general".equals(formatstringparts[1].toLowerCase())) {
                formattedvalue = new CellGeneralFormatter().format(cellvalue);
               } else {
                formattedvalue = new CellNumberFormatter(formatstringparts[1]).format(cellvalue);
               }
              }
              if (cellvalue == 0) {
               if ("general".equals(formatstringparts[2].toLowerCase())) {
                formattedvalue = new CellGeneralFormatter().format(cellvalue);
               } else {
                formattedvalue = new CellNumberFormatter(formatstringparts[2]).format(cellvalue);
               }
              }
             break;
             case 2:
              if (cellvalue >= 0) {
               if ("general".equals(formatstringparts[0].toLowerCase())) {
                formattedvalue = new CellGeneralFormatter().format(cellvalue);
               } else {
                formattedvalue = new CellNumberFormatter(formatstringparts[0]).format(cellvalue);
               }
              }
              if (cellvalue < 0) {
               if ("general".equals(formatstringparts[1].toLowerCase())) {
                formattedvalue = new CellGeneralFormatter().format(cellvalue);
               } else {
                formattedvalue = new CellNumberFormatter(formatstringparts[1]).format(cellvalue);
               }
              }
             break;
             default:
              if ("general".equals(formatstringparts[0].toLowerCase())) {
               formattedvalue = new CellGeneralFormatter().format(cellvalue);
              } else {
               formattedvalue = new CellNumberFormatter(formatstringparts[0]).format(cellvalue);
              }    
             }
    
           }
    
           System.out.println(formattedvalue);
    
          break;
    
          //...
    
          default:
           System.out.println();
         }
        }
       }
    
      } catch (InvalidFormatException ifex) {
      } catch (FileNotFoundException fnfex) {
      } catch (IOException ioex) {
      }
     }
    }
    

    重要提示:

    此代码示例来自 2016 年,适用于 apache poi 3.14

    从当前的 apache poi 版本开始,3.174.x.y 不应再使用。在当前版本中,这很简单:

    ...
       InputStream inp = new FileInputStream("workbook.xlsx");
       Workbook wb = WorkbookFactory.create(inp);
    
       Sheet sheet = wb.getSheetAt(0);
    
       DataFormatter formatter = new DataFormatter();
    
       for (Row row : sheet) {
        for (Cell cell : row) {
         String formattedvalue = formatter.formatCellValue(cell);
         System.out.println("Using DataFormatter: " + formattedvalue);
        }
       }
    ...
    

    【讨论】:

    • 像魅力一样工作。谢谢。
    • 我在规则处理方面遇到了类似的问题。你知道我可以用来在文档中找到更多关于这个的任何类名或方法吗?我应该为它创建一个新帖子吗?
    • 你的意思是条件格式规则?这不是微不足道的。您可以使用sheet.getSheetConditionalFormatting() 从工作表中获取SheetConditionalFormatting,然后遍历所有ConditionalFormattings 并测试您拥有的单元格是否在CellRangeAddress[] 内,如果是,则遍历所有ConditionalFormattingRules并获取已定义的格式。是的,请就此提出具体问题。
    • 需要注意的是,数字类型可以格式化为文本。除了检查“General”格式之外,应用程序程序员还应该检查“@”文本格式。
    • @JonathanDavidArndt:新的DataFormatter 考虑了@ 文本格式。我的代码仅适用于数字单元格类型(以防cell.getCellType() 返回NUMERIC)。如果单元格是@ 文本格式,则cell.getCellType() 返回STRING
    【解决方案2】:

    你可以试试这个

               row = sheet.getRow(RowNo);
               // RowNo on which Row cell should have appeared
               cell = row.getCell(CellNo);
               // CellNo on which Position cell should have appeared on Row
               cell.setCellValue("031642153283700100");
    
      // You could also get CellFormula by using cell.getCellFormula();
    

    【讨论】:

    • 我的目标是在终端中显示值“031642153283700100”(当前单元格值“42153283700100”使用 .xlsx 文件中描述的自定义格式格式化)。我正在尝试找到一种从工作簿中收集格式和单元格信息的方法。我不想修改当前单元格的值。
    • @Geo 为了显示你可以试试 System.out.println(cell.getStringCellValue());如果是数值,您可以使用 cell.getNumericCellValue()
    • 您能否提供有关 .xls 文件的信息以获得更好的帮助!
    • 使用 cell.getCellType() 找到的原始类型返回 0 表示 CELL_TYPE_NUMERIC。 cell.getNumericCellValue() 返回“42155609022100” 我将它添加到上面的列表中。你可以看到我之前已经使用 cell.setCellType(Cell.CELL_TYPE_STRING) 尝试过 cell.getStringCellValue() 。扩展名是 .xlsx 而不是 .xls,我认为这对 HSSF/XSSF 的使用很重要。我将添加更多图片以最好地描述情况。
    猜你喜欢
    • 1970-01-01
    • 2016-08-27
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-03
    • 1970-01-01
    相关资源
    最近更新 更多