apache poi, значения усечения DataFormatter после десяти десятичных разрядов - PullRequest
0 голосов
/ 25 сентября 2018

Итак, у меня есть простой код, который заполняет значения в базе данных

try {
    for(int indexRow = 1; indexRow < numberOfRecords; indexRow++) {
        record = new String[noOfColumns];
        for(int indexColumn = 0;indexColumn < noOfColumns; indexColumn++) {
            indexError = indexColumn;
            String value = "";
            XSSFRow row = sheet.getRow(indexRow);
            if(row != null) {
                XSSFCell cell = sheet.getRow(indexRow).getCell(indexColumn);

                if(cell != null) {
                    value = fmt.formatCellValue(cell);
                }
                record[indexColumn] = value;
            }
        }
        records.add(record);
    }
}

Теперь я также пробежался по исходному коду, но не могу найти способ, которым я могу установить DataFormatter по умолчанию способомчто он может изменить десятичный формат таким образом, чтобы учесть дополнительные изменения.Любая помощь будет принята с благодарностью.Например: в Excel у меня есть -5.57055337362326, но через код он записывает в БД как -5.5705533736

Ответы [ 2 ]

0 голосов
/ 25 сентября 2018

Важно : Цель метода DataFormatter.formatCellValue() - вернуть значение ячейки так, как оно показано в документе Excel .

Допустим, еслиВы зададите числовой формат в Excel , чтобы отобразить 4 дробных цифры, и ваш документ будет выглядеть так:

Excel, 4 fractional digits

Ваш образец кода вернется-5,5706;если вы измените числовой формат для отображения 8 дробных цифр - результат будет -5,57055337.

По умолчанию числовой формат в Excel основан на 10 цифрах (в Apache POI * 1024).* проверьте ExcelGeneralNumberFormat.decimalFormat константу), и похоже, что он используется в вашем документе на основе ваших выходных данных.


Решение

Как упоминается @samabcde(добавив мой ответ, чтобы исправить пару вопросов в своем ответе и предоставить дополнительную информацию), решение состоит в том, чтобы использовать cell.getNumericCellValue() вместо:

    DecimalFormat decimalFormat = new DecimalFormat("#.###############");
    String cellValue = decimalFormat.format(cell.getNumericCellValue());

Здесь мы использовали формат "#.###############" с 15 цифрами с тех пор, как он* Максимальная точность для Excel >>


Дополнительная информация

  1. Обратите внимание на эту статью: При чтении Excelс POI, остерегайтесь плавающих точек

  2. С точки зрения конфигурации DataFromatter вы можете установить формат номера по умолчанию, используя DataFormatter#setDefaultNumberFormat(Format format), и он будет использоваться при вызовеformat.formatCellValue(cell), но только в случае использования неизвестных / неработающих форматов в Excel документ.


PS: Ответ на первый комментарий

Из вашего комментария не до конца понятны все случаи, когда выхочу охватить, предполагается, что DataFormatter работает для вас во всех случаях, кроме числовых значений, и шаблон DecimalFormat с "#.###############" работает в этом случае для вас.В любом случае, если вам нужна более конкретная логика, потребуется просто проверить некоторые другие условия.

Пожалуйста, найдите служебный метод, который вы можете использовать в этом случае:

private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("#.###############");
private static final DataFormatter DATA_FORMATTER = new DataFormatter();

public static String formatCellValue(HSSFCell cell) {
    if (cell != null && cell.getCellTypeEnum() == CellType.NUMERIC
            && !DateUtil.isCellDateFormatted(cell)) {
        return DECIMAL_FORMAT.format(cell.getNumericCellValue());
    } else {
        return DATA_FORMATTER.formatCellValue(cell);
    }
}

Для Excel файл ниже:

Different formats

  • Поле A1 имеет формат 4 дробных цифры с действительным значением 28,9999999999999
  • Поле A2 имеет формат 4 дробных знака с действительным значением -5.5
  • Поле A3 имеет формат по умолчанию Excel с реальным значением 28,9999999999999

Приведенный выше метод служебной программы будет возвращать реальные значения, то есть: 28,9999999999999, -5.5и 28,9999999999999

DataFormatter.formatCellValue() вернет значения, как они выглядят в самом Excel , то есть: 29,0000, -5,5000 и 29.

0 голосов
/ 25 сентября 2018

Причина потери цифры

Приведенный ниже код взят из POI версии 3.14, для метода DataFormatter.formatCellValue с числовой ячейкой в ​​конечном итоге будет вызван метод getFormattedNumberString.Код:

private String getFormattedNumberString(Cell cell, ConditionalFormattingEvaluator 
    cfEvaluator) {

    Format numberFormat = getFormat(cell, cfEvaluator);
    double d = cell.getNumericCellValue();
    if (numberFormat == null) {
        return String.valueOf(d);
    }
    String formatted = numberFormat.format(new Double(d));
    return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation
}

numberFormat будет DecimalFormat с 10 десятичными знаками по умолчанию, предположим, что вы не установили формат, ячейка со значением '-5.57055337362326' вернется '-5.5705533736 ', как и ожидалось.

Решение

Если требуется только точное значение, используйте метод cell.getNumericValue и создайте DecimalFormat, чтобы решить эту проблему.Если требуется изменить отображение в Excel, то нам нужно создать пользовательский DataFormatter.Оба решения проиллюстрированы в следующем примере:

import java.io.IOException;
import java.text.DecimalFormat;

import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

public class TestDataFormatter {
    public static void main(String[] args) throws IOException {
        Double testValue = Double.valueOf("-5.57055337362326");
        System.out.println("test value:\t\t" + testValue.toString());
        XSSFWorkbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet();
        Row row = sheet.createRow(0);
        Cell cell = row.createCell(0);
        cell.setCellValue(testValue);

        // 10 decimal place shown by default 
        DataFormatter dataFormatter = new DataFormatter();
        String defaultFormatted = dataFormatter.formatCellValue(cell);
        System.out.println("default formatted:\t" + defaultFormatted);

        // Create custom format
        XSSFCellStyle style = workbook.createCellStyle();
        DataFormat customDataFormat = workbook.createDataFormat();
        int dataFormatIndex = customDataFormat.getFormat("0.00000000000000");
        style.setDataFormat(dataFormatIndex);
        cell.setCellStyle(style);
        String customFormatted = dataFormatter.formatCellValue(cell);
        System.out.println("custom formatted:\t" + customFormatted);

        // Get numeric value and then format by DecimalFormat
        System.out.println("get numeric:\t\t" + cell.getNumericCellValue());
        System.out.println(
                "format numeric:\t\t" + new DecimalFormat("0.00000000000000").format(cell.getNumericCellValue()));
        workbook.close();
    }
}
...