В разработке корпоративных приложений рано или поздно приходиться работать с различными электронными документами: таблицами и текстовыми документами (в основном в форматах .xls, .xlsx, .doc, .docx). В Java для этих целей существует чудесная библиотека с открытым исходным кодом: Apache POI. При всей прекрасности и удобности этого решения, порой некоторые аспекты его работы вызывают недоумение, их я и предлагаю рассмотреть.
Пустой ли файл?
Первое, с чем мне пришлось столкнуться — элементарная проверка на то, является ли страница пустой. Так как чтение документации — занятие неблагодарное, я сразу начал искать методы с подходящей моим целям сигнатурой. На свое "счастье", первым я встретил метод Sheet#getLastRowNum. И не было предела моему удивлению, когда оказалось, что он возвращает 0 и для абсолютно пустой страницы, и для страницы с одной (самой первой строкой).
Увы и ах, но документацию пришлось почитать. А ларчик просто открывался — метод Sheet#getPhysicalNumberOfRows возвращает нужное значение (0, если строк нет, иначе что-то большее нуля).
Давайте же все-таки вчитаемся в документацию и попытаемся понять, что делает каждый метод.
Метод Sheet#getLastRowNum
возвращает индекс последней строки с данными (считая с нуля). Важно понимать, что пустые строки тоже будут посчитаны. Так, если в таблице данные содержатся только на строке 46, метод вернет значение 45.
Метод же Sheet#getPhysicalNumberOfRows
возвращает число непустых строк в таблице (что считается пустой строкой — вопрос интересный). Так, в предыдущем примере было бы возвращено значение 1.
А откуда строка?
При дальнейшей работе стали появляться фантомные строки, не содержащие данных. Их можно было получить по индексу, они появлялись при переборе через итератор, считались методом Sheet#getPhysicalNumberOfRows
, и содержали несколько ячеек с типом CellType#BLANK
.
Это неочевидно на первый взгляд, но какое-либо дополнительное форматирование влияет на ячейку, а потому она будет явно создана в структуре таблицы и считана Apache POI. Да, даже если это форматирование текста в пустой ячейке. Потому я написал небольшой вспомогательный метод для проверки строки на то, является ли она пустой.
public static boolean isEmpty(Row row) {
Iterator<Cell> iter = row.cellIterator();
while (iter.hasNext()) {
Cell next = iter.next();
switch (next.getCellTypeEnum()) {
case BOOLEAN:
case NUMERIC:
case FORMULA:
return false;
case STRING:
if (!next.getStringCellValue().trim().isEmpty()) {
return false;
}
}
}
return true;
}
Возможно, мой опыт окажется кому-то полезным.
Засим откланиваюсь, прощайте.