Java ApachePOI如何添加自定义数据格式化程序,以将13位整数作为字符串而不是数字进行处理

Java ApachePOI如何添加自定义数据格式化程序,以将13位整数作为字符串而不是数字进行处理,java,excel,apache-poi,Java,Excel,Apache Poi,我正在构建一个XLSX处理器,将XLSX转换为CSV文件。因为文件可能会变得很大,所以我使用基于事件的方法使用XSSFSheetXMLHandler 这工作得非常好,但我的XLSX文件包含长数字(13位),它们是唯一的标识号,而不是实数。在Windows机器上运行我的代码时,它会正确地提取数字,但在Linux机器上运行时,它会将其转换为电子符号 例如:源值为7401075293087。在windows上,该值被正确地提取到我的CSV中,但在Linux上,该值为7.40108E+12 XSSFSh

我正在构建一个XLSX处理器,将XLSX转换为CSV文件。因为文件可能会变得很大,所以我使用基于事件的方法使用XSSFSheetXMLHandler

这工作得非常好,但我的XLSX文件包含长数字(13位),它们是唯一的标识号,而不是实数。在Windows机器上运行我的代码时,它会正确地提取数字,但在Linux机器上运行时,它会将其转换为电子符号

例如:源值为7401075293087。在windows上,该值被正确地提取到我的CSV中,但在Linux上,该值为7.40108E+12

XSSFSheetXMLHandler的问题是,它在封面下读取XLSX,然后抛出SheetContentsHandler捕获的事件,您需要实现这些事件。SheetContentsHandler中的一个方法是带有签名的cell方法:cell(String cellReference、String formattedValue、XSSFComment comment comment comment)

正如您所看到的,这个方法已经收到格式化的单元格(因此在我的例子中,它收到“7.40108E+12”)。其余的逻辑都是在幕后进行的

根据我的调查,我相信解决方案在于定义一个自定义数据格式化程序,它将专门将13位整数作为字符串处理,而不是将它们格式化为电子符号

不幸的是,我的计划没有如预期的那样奏效,我无法在网上找到帮助。下面是我的代码摘录。我在processSheet方法中尝试了以下操作:

     Locale locale = new Locale.Builder().setLanguage("en").setRegion("ZA").build(); 
     DataFormatter formatter = new DataFormatter(locale);
     Format format = new MessageFormat("{0,number,full}");
     formatter.addFormat("#############", format);
以下是我的代码摘录:

守则的主体:

 public void process(String Filename)throws IOException, OpenXML4JException, ParserConfigurationException, SAXException {
     ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(this.xlsxPackage);
     XSSFReader xssfReader = new XSSFReader(this.xlsxPackage);
     StylesTable styles = xssfReader.getStylesTable();
     XSSFReader.SheetIterator iter = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
     while (iter.hasNext()) {
          InputStream stream = iter.next();
          String sheetName = iter.getSheetName();
          outStream = new FileOutputStream(Filename);
          logger.info(sheetName);
          this.output = new  PrintWriter(Filename);
          processSheet(styles, strings, new SheetToCSV(), stream);
          logger.info("Done with Sheet   :"+sheetName);
          output.flush();
          stream.close();
          outStream.close();
          output.close();
         ++index; 
     }
 } 

 public void processSheet(StylesTable styles,ReadOnlySharedStringsTable strings,SheetContentsHandler sheetHandler, InputStream sheetInputStream)
         throws IOException, ParserConfigurationException, SAXException {

     InputSource sheetSource = new InputSource(sheetInputStream);
     try {
         XMLReader sheetParser = SAXHelper.newXMLReader();
         ContentHandler handler = new XSSFSheetXMLHandler(styles, null, strings, sheetHandler, formatter, false);
         sheetParser.setContentHandler(handler);
         sheetParser.parse(sheetSource);
      } catch(ParserConfigurationException e) {
         throw new RuntimeException("SAX parser appears to be broken - " + e.getMessage());
      }
 }
下面是自定义处理程序:

private class SheetToCSV implements SheetContentsHandler {
         private boolean firstCellOfRow = false;
         private int currentRow = -1;
         private int currentCol = -1;

     private void outputMissingRows(int number) {

         for (int i=0; i<number; i++) {
             for (int j=0; j<minColumns; j++) {
                 output.append(',');
             }
             output.append('\n');
         }
     }

     public void startRow(int rowNum) {
         // If there were gaps, output the missing rows
         outputMissingRows(rowNum-currentRow-1);
         // Prepare for this row
         firstCellOfRow = true;
         currentRow = rowNum;
         currentCol = -1;
     }

     public void endRow(int rowNum) {
         // Ensure the minimum number of columns
         for (int i=currentCol; i<minColumns; i++) {
             output.append(',');
         }
         output.append('\n');
     }

     public void cell(String cellReference, String formattedValue,
             XSSFComment comment) {
         logger.info("CellRef :: Formatted Value   :"+cellReference+" :: "+formattedValue);              
         if (firstCellOfRow) {
             firstCellOfRow = false;
         } else {
             output.append(',');
         }

         // gracefully handle missing CellRef here in a similar way as XSSFCell does
         if(cellReference == null) {
             cellReference = new CellRangeAddress(currentRow, currentCol, currentCol, currentCol).formatAsString();
         }

         // Did we miss any cells?
         int thisCol = (new CellReference(cellReference)).getCol();
         int missedCols = thisCol - currentCol - 1;
         for (int i=0; i<missedCols; i++) {
             output.append(',');
         }
         currentCol = thisCol;

         // Number or string?
         try {
             Double.parseDouble(formattedValue);
             output.append(formattedValue);
         } catch (NumberFormatException e) {
             //formattedValue = formattedValue.replaceAll("\\t", "");
             //formattedValue = formattedValue.replaceAll("\\n", "");
             //formattedValue = formattedValue.trim();
             output.append('"');
             output.append(formattedValue.replace("\"", "\\\"").trim());
             output.append('"');
         }
     }

     public void headerFooter(String text, boolean isHeader, String tagName) {
         // Skip, no headers or footers in CSV
     }

    @Override
    public void ovveriddenFormat(String celRef, int formatIndex,
            String formatedString) {
        // TODO Auto-generated method stub

    }

 }
私有类SheetToCSV实现SheetContentsHandler{
private boolean firstfrow=false;
private int currentRow=-1;
private int currentCol=-1;
私有void outputMissingRows(整数){

对于(int i=0;iDZONE,他写了一篇关于这一点的精彩文章:

StackOverflow的另一个答案是:

Row row = sheet.getRow(0);
Object o = getCellValue(row.getCell(0));
System.out.println(new BigDecimal(o.toString()).toPlainString());
参考:


我没有在linux机器上测试您的实际问题……但是我希望这能在深夜提供一些答案!

DZONE写了一篇关于这个问题的精彩文章:

StackOverflow的另一个答案是:

Row row = sheet.getRow(0);
Object o = getCellValue(row.getCell(0));
System.out.println(new BigDecimal(o.toString()).toPlainString());
参考:


我没有在linux机器上测试您的实际问题。但是,我希望这能在深夜提供一些答案!

如果文件是使用
Excel
生成的,并且包含13位数字的单元格是使用数字格式
0
而不是
生成的,则无法复制l

但“在Linux机器上运行”意味着什么?如果我正在使用
Libreoffice Calc
创建
*.xlsx
文件,并使用数字格式
General
对包含13位数字的单元格进行格式化,则
Calc
将以13位数字显示,但
Excel
不会。要在
Excel
中显示13位数字,单元格必须使用数字格式
0
#
进行格式化

apache-poi
DataFormatter
的工作方式与
Excel
类似。当使用
General
进行格式化时,
Excel
将12位数字的值显示为科学符号

您可以使用以下方法更改此行为:

...
    public void processSheet(
            StylesTable styles,
            ReadOnlySharedStringsTable strings,
            SheetContentsHandler sheetHandler, 
            InputStream sheetInputStream) throws IOException, SAXException {
        DataFormatter formatter = new DataFormatter();
        formatter.addFormat("General", new java.text.DecimalFormat("#.###############"));
...

如果文件是使用
Excel
生成的,并且包含13位数字的单元格是使用数字格式
0
#
常规
格式化的,则无法复制

但“在Linux机器上运行”意味着什么?如果我正在使用
Libreoffice Calc
创建
*.xlsx
文件,并使用数字格式
General
对包含13位数字的单元格进行格式化,则
Calc
将以13位数字显示,但
Excel
不会。要在
Excel
中显示13位数字,单元格必须使用数字格式
0
#
进行格式化

apache-poi
DataFormatter
的工作方式与
Excel
类似。当使用
General
进行格式化时,
Excel
将12位数字的值显示为科学符号

您可以使用以下方法更改此行为:

...
    public void processSheet(
            StylesTable styles,
            ReadOnlySharedStringsTable strings,
            SheetContentsHandler sheetHandler, 
            InputStream sheetInputStream) throws IOException, SAXException {
        DataFormatter formatter = new DataFormatter();
        formatter.addFormat("General", new java.text.DecimalFormat("#.###############"));
...

Tx Axel。你的建议帮我解决了问题。关于你的其他评论:不幸的是,我对源文件的格式没有任何控制权,所以我必须处理我得到的(我得到了许多不同的格式,所以尝试通用).W.r.t comment re Linux machine:My main dev box是一台Ubuntu 16.04计算机,它给出了如上所述的错误。当我在客户的Windows笔记本电脑上运行代码时,错误没有发生。完全相同的文件,完全相同的代码库。因此,我假设这是某个特定于语言环境的问题。为了记录,我添加了如下格式:formatter、 addFormat(“General”,新java.text.DecimalFormat(“General”);这是必要的,因为我的XLSX中的其他字段包含0.00160455519952056Tx Axel之类的值。您的建议将我分类。关于您的其他评论:不幸的是,我无法控制源文件的格式,因此我必须处理我得到的内容(我得到许多不同的格式,因此尝试通用).W.r.t comment re Linux machine:My main dev box是一台Ubuntu 16.04计算机,它给出了如上所述的错误。当我在客户的Windows笔记本电脑上运行代码时,错误没有发生。完全相同的文件,完全相同的代码库。因此,我假设这是某个特定于语言环境的问题。为了记录,我添加了如下格式:formatter、 addFormat(“General”,new java.text.DecimalFormat(“General”,new java.text.DecimalFormat)(“General”,new java.text.DecimalFormat”(“General”),新java.text.DecimalFormat(“General”),新java