Пример чтения файлов Excel

На странице описания библиотеки Apache POI представлены свойства и методы взаимодействия Java приложений с файлами Excel. Здесь рассматривается пример использования Apache POI для чтения файлов Excel 2007 или более поздней версии. Если необходимо обрабатывать Excel 1997-2003, то следует использовать классы, наименования которых начинаются с символа 'H' (см. наименование классов на странице описания Apache POI).

Открытие книги Excel

Чтобы «открыть» файл Excel как HSSFWorkbook (.xls), так и XSSFWorkbook (.xlsx) можно использовать либо File, либо InputStream. При использовании InputStream требуется больше памяти для загрузки файла в буффер.

Метод openBook демонстрирует использование WorkbookFactory для открытия Excel файла. Строки использования InputStream закомментированы.

private XSSFWorkbook book;
...
private void openBook(final String path)
{
    try {
        File file = new File(path);
        book = (XSSFWorkbook) WorkbookFactory.create(file);

//      InputStream is = new FileInputStream(FILE);
//      book = (XSSFWorkbook) WorkbookFactory.create(is);
//      is.close();
    } catch (FileNotFoundException e1) {
        e.printStackTrace();
    } catch (EncryptedDocumentException e) {
        e.printStackTrace();
    } catch (InvalidFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Если нужно обойти использование WorkbookFactory, т.е. использовать XSSFWorkbook (HSSFWorkbook) напрямую, то следует использовать OPCPackage (.xlsx) или NPOIFSFileSystem (.xls).

private XSSFWorkbook book;
...
private void openBookDirectly(final String path)
{
    File file = new File(path);
    try {
        OPCPackage pkg = OPCPackage.open(file);
        book = new XSSFWorkbook(pkg);
        pkg.close();
    } catch (InvalidFormatException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Открытие страницы

При открытии страницы слеудет использовать метод getSheet с указанием в качестве параметра наименования страницы. Здесь необходимо быть внимательным, поскольку наименования страницы по умолчанию могут быть как «Sheet», так и «Лист», в зависимости от локализации операционной системы и Excel.

XSSFSheet sheet = book.getSheet("Лист1");

Перебор строк и ячеек

Чтобы «пройтись» по всем страницам книги и перебрать все значения в ячейках можно использовать итераторы. Следующий код показывает использование итераторов для перебора всех ячеек страницы.

import java.util.Iterator;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Cell;
...
Iterator<Row> ri = sheet.rowIterator();

while(ri.hasNext()) {
    XSSFRow row = (XSSFRow) ri.next();

    Iterator<Cell> ci = row.cellIterator();

    while(ci.hasNext()) {
        XSSFCell cell = (XSSFCell) ci.next();
        // код
    }
}

Итераторы доступны по вызовам workbook.sheetIterator(), sheet.rowIterator() и row.cellIterator(). Но необходимо помнить, что rowIterator и cellIterator перебирают только строки и ячейки, которые созданы, пропуская пустые строки и ячейки.

Если необходимо проверить все строки и все ячейки определенной области, то можно воспользоваться следующим кодом.

private void readCells()
{
    // Определение граничных строк обработки
    int rowStart = Math.min(  0, sheet.getFirstRowNum());
    int rowEnd   = Math.max(100, sheet.getLastRowNum ());

    for (int rw = rowStart; rw < rowEnd; rw++) {
        XSSFRow row = sheet.getRow(rw);
        if (row == null) {
            // System.out.println(
            //      "row '" + rw + "' is not created");
            continue;
        }
        short minCol = row.getFirstCellNum();
        short maxCol = row.getLastCellNum();

        for(short col = minCol; col < maxCol; col++) {
            XSSFCell cell = row.getCell(col);
            if (cell == null) {
                // System.out.println(
                //   "cell '" + col + "' is not created");
                continue;
            }
            printCell(row, cell);
        }
    }
}

В представленном коде для чтения ячейки был использован метод getCell(int). Можно использовать метод getCell(int, MissingCellPolicy), где MissingCellPolicy, определяет условие возвращения пустых и отсутствующих ячеек. Однако IDE Eclipse, где работоспособность кода проверялась, показывает, что MissingCellPolicy упразднена (deprecated), а метод getCell(int) для ячейки типа XSSFCell вернул правильные значения. Определение значений ячеек выполнялось в методе printCell(row, cell).

Чтение содержимого ячейки

Чтобы получить значение ячейки, необходимо знать тип её значения. Полагаю, что Вы не раз сталкивались с числовым представлением значения даты. Если у текстовой ячейки попытаться получить числовое значение, то будет вызвано NumberFormatException. Поэтому, необходимо первоначально определиться с типом, чтобы использовать соответствующий метод.

Следующий код в цикле проходит по ячейкам в строке и выводит в консоль ссылочную информацию на ячейку (например $A$3) и содержимое ячейки. Причем, сначала отображается значение, полученное методом formatCellValue класса DataFormatter, а после символа слеша '/' отображается значение, получаемое методами getRichStringCellValue(), getDateCellValue(), getNumericCellValue(), getBooleanCellValue() и getCellFormula() класса XSSFCell.

private void printCell(XSSFRow row, XSSFCell cell)
{
    DataFormatter formatter = new DataFormatter();
    CellReference cellRef = new CellReference(row.getRowNum(),
                                              cell.getColumnIndex());
    System.out.print(cellRef.formatAsString());
    System.out.print(" : ");

    // get the text that appears in the cell by getting 
    // the cell value and applying any data formats
    // (Date, 0.00, 1.23e9, $1.23, etc)
    String text = formatter.formatCellValue(cell);
    System.out.print(text + " / ");

    // Вывод значения в консоль
    switch (cell.getCellTypeEnum()) {
    case STRING:
        System.out.println(cell.getRichStringCellValue()
                               .getString());
        break;
    case NUMERIC:
        if (DateUtil.isCellDateFormatted(cell))
            System.out.println(cell.getDateCellValue());
        else
            System.out.println(cell.getNumericCellValue());
        break;
    case BOOLEAN:
        System.out.println(cell.getBooleanCellValue());
        break;
    case FORMULA:
        System.out.println(cell.getCellFormula());
        break;
    case BLANK:
        System.out.println();
        break;
    default:
        System.out.println();
    }
}

Пример чтения файла Excel

Работоспособность представленного на странице кода (методов), была проверена в примере, структура которого изображена на следующем скриншоте. Это проект Eclipse, включающий перечень необходимых библиотек для чтения файла Excel. Основной класс ExcelRead реализует все представленные выше методы.

На следующем скриншоте представлена страница простенького файла Excel, содержащая ячейки со значениями типа Date, String, Numeric и ячейки с формулами.

Результат чтения файла

Значения ячеек книги Excel в примере отображаются в консоли. Обратите внимание на отличия значений до слеша и после него для типов Date и Numeric. При необходимости можно использовать в приложении переменные соответствующего типа (Date, Integer) и должным образом отформатировать значения.


Книга Excel открыта
Страница открыта

$A$1 : Закупки / Закупки
$B$1 : 1/20/17 / Fri Jan 20 00:00:00 MSK 2017
$A$3 : Наименование / Наименование
$B$3 : Цена / Цена
$C$3 : Количество / Количество
$D$3 : Стоимость / Стоимость
$A$4 : Сахар / Сахар
$B$4 : 50 / 50.0
$C$4 : 2 / 2.0
$D$4 : B4*C4 / B4*C4
$A$5 : Рис / Рис
$B$5 : 45 / 45.0
$C$5 : 4 / 4.0
$D$5 : B5*C5 / B5*C5
$A$7 : Итого : / Итого :
$D$7 : SUM(D4:D6) / SUM(D4:D6)
 

Скачать примеры

Исходный пример, рассмотренный в тексте страницы, можно скачать здесь (11.7 Мб).

  Рейтинг@Mail.ru