2011-06-28 7 views
21

Zdaję sobie sprawę, że to pytanie jest trochę mylące, ale nie wiedziałem, jak inaczej to wyrazić. W każdym razie, tutaj jest oryginalny kod:Podczas pobierania zawartości komórki za pomocą biblioteki Apache-POI, pojawia się komunikat "Nie można uzyskać wartości liczbowej z komórki tekstowej" i odwrotnie. Jak mogę to naprawić?

private void readFile(String excelFileName) throws FileNotFoundException, IOException { 
    XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(excelFileName)); 
    if (workbook.getNumberOfSheets() > 1){ 
     System.out.println("Please make sure there is only one sheet in the excel workbook."); 
    } 
    XSSFSheet sheet = workbook.getSheetAt(0); 
    int numOfPhysRows = sheet.getPhysicalNumberOfRows(); 
    XSSFRow row; 
    XSSFCell num; 
    for(int y = 1;y < numOfPhysRows;y++){ //start at the 2nd row since 1st should be category names 
     row = sheet.getRow(y); 
     poNum = row.getCell(1); 
     item = new Item(Integer.parseInt(poNum.getStringCellValue()); 
     itemList.add(item); 
     y++; 
    } 
} 

private int poiConvertFromStringtoInt(XSSFCell cell){ 
    int x = Integer.parseInt(Double.toString(cell.getNumericCellValue())); 
    return x; 
} 

otrzymuję następujący błąd:

Exception in thread "main" java.lang.IllegalStateException: Cannot get a numeric value from a text cell 
    at org.apache.poi.xssf.usermodel.XSSFCell.typeMismatch(XSSFCell.java:781) 
    at org.apache.poi.xssf.usermodel.XSSFCell.getNumericCellValue(XSSFCell.java:199) 

Nawet jeśli zmienię go dostać albo ciąg używając XSSFCell.getStringCellValue() lub nawet XFFSCell.getRichTextValue, otrzymuję odwrocie powyższy komunikat o błędzie (i upewniam się, że ostatecznie zrobię to int używając Integer.parseInt(XSSFCell.getStringCellValue()).

Błąd odczytuje:

Exception in thread "main" java.lang.IllegalStateException: Cannot get a text value from a numeric cell 
    at org.apache.poi.xssf.usermodel.XSSFCell.typeMismatch(XSSFCell.java:781) 
    at org.apache.poi.xssf.usermodel.XSSFCell.getNumericCellValue(XSSFCell.java:199) 

Wiem na fakt, że kolumna arkusza kalkulacyjnego Excel w rzeczywistości ciąg. Nie mogę zmienić arkusza programu Excel, gdy jest on przesyłany, gdzie zawsze przy użyciu tego samego formatu i formatowania każda kolumna najpierw zajmuje dużo czasu przetwarzania.

Wszelkie sugestie?

[Rozwiązanie] Oto kod rozwiązanie wymyśliłem od @ pomocy Wivani za:

private long poiGetCellValue(XSSFCell cell){ 
    long x; 
    if(cell.getCellType() == 0) 
     x = (long)cell.getNumericCellValue(); 
    else if(cell.getCellType() == 1) 
     x = Long.parseLong(cell.getStringCellValue()); 
    else 
     x = -1; 
    return x; 
} 
+0

Sprawdź API; istnieją metody sprawdzania typu kolumny, więc możesz jej użyć do sprawdzenia, czy musisz dokonać konwersji, czy nie. PS Ten fragment kodu jest niewystarczający, aby naprawdę pomóc w debugowaniu. – Wivani

+0

Aby wszyscy wiedzieli, co się stało, dowiedziałem się, że pierwsze 100 lub więcej liczb miało wiodącą 0. To spowodowało, że Excel automatycznie uczynił z tego ciąg. Musiałem więc napisać metodę, aby najpierw sprawdzić typ, a następnie odpowiednio sformatować. Dziękujemy @Wivani – crstamps2

+0

Interesujące może być na przyszłość, aby dodać swój "kod rozwiązania"? – Wivani

Odpowiedz

50
Use This as reference 

switch (cell.getCellType()) { 
       case Cell.CELL_TYPE_STRING: 
        System.out.println(cell.getRichStringCellValue().getString()); 
        break; 
       case Cell.CELL_TYPE_NUMERIC: 
        if (DateUtil.isCellDateFormatted(cell)) { 
         System.out.println(cell.getDateCellValue()); 
        } else { 
         System.out.println(cell.getNumericCellValue()); 
        } 
        break; 
       case Cell.CELL_TYPE_BOOLEAN: 
        System.out.println(cell.getBooleanCellValue()); 
        break; 
       case Cell.CELL_TYPE_FORMULA: 
        System.out.println(cell.getCellFormula()); 
        break; 
       default: 
        System.out.println(); 
      } 
+0

Dzięki, ale przypadki powinny być 'XSSFCell.CELL_TYPE _...' –

+0

@Mayank Dodaj rzut na System.out.println (cell.getNumericCellValue()); aby uzyskać wartość całkowitą, ponieważ instrukcja avove zwraca wartość podwójną. Tak więc poprawna odpowiedź na wartość interger to System.out.println ((int) cell.getNumericCellValue()); –

+0

@Mayank Konwertuj RichStringCellValue na normalny łańcuch za pomocą toString(), aby uzyskać wartość ciągu, która może być przechowywana wewnątrz zmiennej łańcuchowej. Tak więc odpowiedź brzmi: System.out.println (cell.getRichStringCellValue(). GetString(). ToString()); –

21

Wystarczy użyć cell.setCellType (1); przed odczytaniem wartości komórki i otrzymaniem jej jako String zawsze, po tym możesz użyć jej we własnym formacie (typ).

Ravi

+1

Nie jest to zalecane, ponieważ spowoduje utratę wszystkich informacji o formatowaniu komórek. – Gagravarr

+0

"Myślę, że" zrobienie tego może spowodować, że nie odda pól dat tak, jak byś tego chciał ... o czym należy pamiętać, jeśli to jest problem. – BVernon

0

rozwiązanie Raviego działa: Wystarczy użyć cell.setCellType (1); przed odczytaniem wartości komórki i otrzymaniem jej jako String zawsze, po tym możesz użyć jej we własnym formacie (typ).

21

można uzyskać wartość jako String przy użyciu formatu zdefiniowanego dla tej komórki:

final DataFormatter df = new DataFormatter(); 
final XSSFCell cell = row.getCell(cellIndex); 
String valueAsString = df.formatCellValue(cell); 

Dzięki this answer.

+0

dziękuję, to działało jak czar dla mnie! –

3

Użyj poniższego kodu czytać dowolny typ danych z wykorzystaniem xcels poi.

2

Mam również ten błąd z wersją POI 3.12final.
Myślę, że błąd jest tam zarejestrowany: https://bz.apache.org/bugzilla/show_bug.cgi?id=56702 i umieściłem tam komentarz z moją analizą.

Oto sposób obejścia, którego użyłem: wyjątek został podniesiony przez HSSFCell.getNumericCellValue, który został wywołany przez DateUtil.isCellDateFormatted. DateUtil.isCellDateFormatted robi 2 rzeczy:
1) sprawdź typ wartości komórki, wywołując HSSFCell.getNumericCellValue, a następnie DateUtil.isValidExcelDate(), co wydaje mi się prawie bezcelowe.
2) sprawdzić, czy format komórki jest format daty

skopiowane kod temacie 2) powyżej w nową funkcję „myIsADateFormat” i używali go zamiast DateUtil.isCellDateFormatted (który jest dość brudny skopiować Kod biblioteki, ale działa ...):

private boolean myIsADateFormat(Cell cell){ 
    CellStyle style = cell.getCellStyle(); 
    if(style == null) return false; 
    int formatNo = style.getDataFormat(); 
    String formatString = style.getDataFormatString(); 
    boolean result = DateUtil.isADateFormat(formatNo, formatString); 
    return result; 
} 

Jeśli trzeba najpierw sprawdzić typ wartości, można użyć tego też:

CellValue cellValue = evaluator.evaluate(cell); 
int cellValueType = cellValue.getCellType(); 
if(cellValueType == Cell.CELL_TYPE_NUMERIC){ 
    if(myIsADateFormat(cell){ 
     .... 
    } 
} 
Powiązane problemy