Apache POI. Если вдруг соберетесь что-то творить с excel

Jun 19, 2014 17:51

Библиотека сама по себе очень бодрая. По скорости работы в сравнении со встроенным экселевским VB она словно корабль инопланетян по сравнению с бипланами.

Но есть нюансы.

1. Нельзя скопировать ряд из одной рабочей книги в другую. Похоже, что связано это со стилями ячеек, которые тоже нельзя скопировать напрямую из ячейки одной книги в ячейку другой ибо у каждой рабочей книги свои стили...

2. По идее пустая ячейка - это null или CELL_TYPE_BLANK. Причем, если null, то ее не существует, а если BLANK, значит, в ячейке нет никакого значения. По большой и светлой идее как только мы удалили значение из ячейки, она автоматом должна стать BLANK...

А вот хрен. Она может быть CELL_TYPE_STRING со значением "" (т.е. нулевой длиной). Других пока не встречал (и не проверял), но все может быть...

3. Пустой ячейке нельзя сразу назначить тип CELL_TYPE_NUMERIC.
По какой-то таинственной причине Apache POI при назначении типов именно на CELL_TYPE_NUMERIC пытается считать значение ячейки. Естественно, у только что созданной ячейки значения нет. Библиотека думает (опять хз почему - я не смотрел), что раз ничего нет, значит это text (Cannot get a numeric value from a text cell). А раз text, значит, CELL_TYPE_STRING. А в Numeric никак нельзя считать String.

Сначала я пробовал просто ловить исключение. Исключение ловится. А что назначать? Ну, вообще прокатывал CELL_TYPE_STRING. Но это все же неправильно.
Нашелся способ обхода. Сначала назначить ячейке тип CELL_TYPE_BLANK. А уж после CELL_TYPE_NUMERIC.

В итоге, чтобы скопировать ячейку, нужно написать что-то типа такого:

public static void copyCell (Cell oldCell, Cell newCell) {
// set cell data type
int oct = oldCell.getCellType();

// Just in case we continue to catch Numeric error.
try {
newCell.setCellType(Cell.CELL_TYPE_BLANK);
newCell.setCellType(oct);
} catch (IllegalStateException e) {
System.out.println("Wrong cell type. Using string.");
newCell.setCellType(Cell.CELL_TYPE_STRING);
}

// Set new cell value according old cell data type
switch (oct) {
case Cell.CELL_TYPE_BLANK:
newCell.setCellValue(oldCell.getStringCellValue());
break;
case Cell.CELL_TYPE_STRING:
newCell.setCellValue(oldCell.getRichStringCellValue());
break;
case Cell.CELL_TYPE_NUMERIC:
newCell.setCellValue(oldCell.getNumericCellValue());
break;
case Cell.CELL_TYPE_BOOLEAN:
newCell.setCellValue(oldCell.getBooleanCellValue());
break;
case Cell.CELL_TYPE_ERROR:
newCell.setCellErrorValue(oldCell.getErrorCellValue());
break;
case Cell.CELL_TYPE_FORMULA:
newCell.setCellFormula(oldCell.getCellFormula());
break;
}

// copy comment if exist
if (oldCell.getCellComment() != null) {
newCell.setCellComment(oldCell.getCellComment());
}

// copy hyperlink if exist
if (oldCell.getHyperlink() != null) {
newCell.setHyperlink(oldCell.getHyperlink());
}
}

Ряд, соответственно, копируется втупую:

public static void copyRow (Row source, Row target) {
for (int i = 0; i < source.getLastCellNum(); i++ ) {
Cell oldCell = source.getCell(i);
Cell newCell = target.createCell(i);

if (oldCell == null) {
newCell = null;
} else {
copyCell(oldCell, newCell);
}
}
}

UPD: getRichStringCellValue(), если вы копируете ячейку из одного файла в другой и один из них xls, а второй xlsx, работать не будет - сильно разные форматы, преобразования встроенного нет.

apache poi, java, excel

Previous post Next post
Up