簡體   English   中英

Apache POI如何添加自定義DataFormatter以將13位整數作為字符串而非數字進行處理

[英]Apache POI How to add a custom DataFormatter for handling 13 digit integers as strings, not numbers

我正在構建一個將XLSX轉換為CSV文件的XLSX處理器。 因為文件可能會變得很大,所以我正在使用基於事件的方法,該方法使用XSSFSheetXMLHandler

這工作得很好,但是我的XLSX文件包含長號(13位數字),這是唯一的標識號,而不是實數。 在Windows機器上運行我的代碼時,它會正確提取數字,但是在Linux機器上運行時,它將其轉換為E表示法。

例如:源值為7401075293087。在Windows上,此值已正確提取到我的CSV中,但在Linux上,該值通過7.40108E + 12

XSSFSheetXMLHandler的問題在於,它在幕后讀取XLSX,然后拋出需要實現的SheetContentsHandler捕獲的事件。 SheetContentsHandler中的方法之一是具有簽名的單元格方法:cell(String cellReference,String formattedValue,XSSFComment comment)

如您所見,此方法已經接收到格式化的單元格(因此,在我的情況下,它接收到“ 7.40108E + 12”)。 所有其他邏輯都在幕后進行。

根據我的調查,我認為解決方案在於定義一個自定義DataFormatter,它將特定地將13位整數視為字符串,而不是將其格式化為E表示法。

不幸的是,我的計划沒有按預期工作,我無法在線找到幫助。 下面是我的代碼的一部分。 我在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

    }

 }

如果文件是使用Excel生成的,並且包含13位數字的單元格使用數字格式0#格式化, 而不是 General ,則無法復制。

但是“在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("#.#"));
...

DZONE為此撰寫了一篇開篇文章: https ://dzone.com/articles/simple-string-representation-of-java-decimal-numbe

StackOverflow的另一個答案是:

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

REF: Apache POI DataFormatter返回科學計數法

我沒有在Linux機器上測試您的實際問題。但是,我希望這能在深夜提供一些答案!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM