【问题标题】:apache POI reads text column as numericapache POI 将文本列读取为数字
【发布时间】:2018-07-24 10:43:49
【问题描述】:

我正在开发一个功能,我必须存储通过上传 Excel 文件收到的数字。它是用 Java 编写的,使用 apache poi 库,在 Spring 框架下(无关紧要)。

我正在尝试上传的文件(请注意,该列已设置为文本):

代码如下:

// function accepts "MultipartFile inputFile"
InputStream is = inputFile.getInputStream();
StreamingReader reader = StreamingReader.builder().rowCacheSize(100).bufferSize(4096).sheetIndex(0)
                        .read(is);
for (Row row : reader) {
    System.out.println("Reading next row.");
    System.out.println("row[0] is of type " + row.getCell(0).getCellType());
    Cell cell = row.getCell(0);
    String value = "";
    if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
        value = cell.getStringCellValue().replaceAll("[\\D]", "");
    } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
        value = NumberToTextConverter.toText(cell.getNumericCellValue());
    }
    System.out.println("Value is " + value);
}

我得到低于输出:

Reading next row.
row[0] is of type 0 // Which is equals to Cell.CELL_TYPE_NUMERIC
Value is 166609999

问题是我需要将其读取为“0166609999”而不是“166609999”,奇怪的是,如果我将其保存为 xls 格式并重新上传文件,我对检测其单元格类型没有任何问题。有什么想法吗?

因被标记为重复而编辑:

  • 给定答案https://stackoverflow.com/a/19401902/1131470 使用 DataFormatter 类,当我们流式传输工作表时不支持该类,因为检索到的 Cell 对象将是 StreamingCell 对象,如果我们调用 getCellStyle() 函数,则会引发异常。

截至 2016 年 3 月 29 日

似乎StreamingCell 类不支持DataFormatter,其中DataFormatter 是目前唯一可以获取Excel 显示内容的类。因此,当前的解决方案将坚持将整个 Excel 文件读入内存。如果将来有人找到答案,您可以在此处发布答案,我将不胜感激,因为当前的解决方案绝对是一个糟糕的解决方案。

截至 2016 年 3 月 31 日

特别感谢 Axel 指出其库版本问题,将流媒体 jar 文件更新到 0.2.12 解决了该问题。谢谢!

【问题讨论】:

  • 我怀疑它可能位于github.com/monitorjbl/excel-streaming-reader。因此,请确保您使用的是最新版本。
  • @AxelRichter 非常感谢您指出,是的,当我查看 StreamingCell github.com/monitorjbl/excel-streaming-reader/blob/master/src/… 的类时,似乎大多数函数都会抛出 UnsupportedException。别无选择,但我必须在限制上传大小的同时重新阅读整个文件。
  • 你说的不可能是真的。如果单元格格式为Text,那么对于OpenXML,单元格的类型为t="s",并且单元格的值指向sharedStrings.xml。所以row.getCell(0).getCellType() 不能为 0 且值不能为 166609647。这仅适用于单元格格式为Text 的情况。然后,只有这样,你才需要一个格式化程序。
  • 我还没有将其解压缩为 zip 并查看 Xml 文件。但我已将文件托管在dropbox.com/s/hjz0dletdq3qk1i/test_formatted_number.xlsx?dl=0,您可以抓取并查看您希望的类型,感谢您的帮助 =)

标签: java excel apache apache-poi


【解决方案1】:

已下载您的文件。已下载xlsx-streamer-0.2.12.jarslf4j-api-1.7.20.jarslf4j-nop-1.7.20.jar 并放置在类路径中。

有以下代码:

import com.monitorjbl.xlsx.*;
import org.apache.poi.ss.usermodel.*;

import java.io.*;

class StreamingReaderTest {

 public static void main(String[] args) throws Exception {

  try (
   InputStream is = new FileInputStream(new File("/home/axel/Downloads/test_formatted_number.xlsx"));
   StreamingReader reader = StreamingReader.builder()
           .rowCacheSize(100)
           .bufferSize(4096)
           .sheetIndex(0)
           .read(is);
  ) {
   for (Row row : reader) {
    System.out.println("row[0] is of type " + row.getCell(0).getCellType());
    Cell cell = row.getCell(0);
    String value = "";
    if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
        value = cell.getStringCellValue();
    } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
        value = "" + cell.getNumericCellValue();
    }
    System.out.println("Value is " + value);
   }
  }
 }
}

给我:

所以这里没问题。

如果我将DataFormatter 与数字单元格值一起使用:

import com.monitorjbl.xlsx.*;
import org.apache.poi.ss.usermodel.*;

import java.io.*;

class StreamingReaderTest {

 public static void main(String[] args) throws Exception {

  try (
   InputStream is = new FileInputStream(new File("/home/axel/Downloads/test_formatted_number.xlsx"));
   StreamingReader reader = StreamingReader.builder()
           .rowCacheSize(100)
           .bufferSize(4096)
           .sheetIndex(0)
           .read(is);
  ) {
   for (Row row : reader) {
    System.out.println("row[0] is of type " + row.getCell(0).getCellType());
    Cell cell = row.getCell(0);
    String value = "";
    if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
        value = cell.getStringCellValue();
    } else if (cell.getCellType() == Cell.CELL_TYPE_NUMERIC) {
        value = new DataFormatter().formatCellValue(cell);
    }
    System.out.println("Value is " + value);
   }
  }
 }
}

并将数字 166609647 放入格式为0000000000A2。然后我得到:

【讨论】:

  • 哇,太棒了,让我稍后再试一次你的流媒体 jar 文件版本,希望它能解决我的问题..
  • 确实是版本问题。我的项目使用的是过时的 0.2.3 版本,更新它可以立即解决我的问题,谢谢!
【解决方案2】:

为什么 .replaceAll("[\D]", "");

对我来说很好用,刚刚试过。 想知道这里有什么问题。

fis = new FileInputStream(inputFile);
XSSFWorkbook inputWorkBook = new XSSFWorkbook (fis);
XSSFSheet inputSheet = inputWorkBook.getSheetAt(0);
Iterator<Row> rowIterator = inputSheet.iterator();

while(rowIterator.hasNext())
{
    Row row = rowIterator.next();
    Iterator<Cell> cellIterator = row.cellIterator();

    while (cellIterator.hasNext()) 
    {
        Cell cell = cellIterator.next();

        switch (cell.getCellType())
        {
            case Cell.CELL_TYPE_STRING:
                System.out.print(cell.getStringCellValue() + "\t");
                break;
            case Cell.CELL_TYPE_NUMERIC:
                System.out.print(cell.getNumericCellValue() + "\t");
                break;
            case Cell.CELL_TYPE_BOOLEAN:
                System.out.print(cell.getBooleanCellValue() + "\t");
                break;
            default :  
        }
    }
    System.out.println(""); 
}  

【讨论】:

  • 呃,谢谢你指出奇怪的东西=)但无论如何它不会影响我的问题,因此我现在就留下它..
  • 您好,再次感谢您的努力,很抱歉对这个问题不太清楚。如果我接受 XLS 文件,我会使用与您类似的方法来处理该文件,当我这样做时,'0166609647' 显示正常。当我接受可能非常大的 XLSX 文件时会出现问题,因此首选流式传输而不是将整个文件读入内存,这就是问题发生的地方。
  • 我已经在我的问题上添加了关于如何声明流对象的部分,你再看看那里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-25
  • 2020-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多