Перейти к содержанию

Работа с Microsoft Excel в Java

В этом руководстве продемонстрируем использование API-интерфейсов Apache POI и JExcel для работы с электронными таблицами Excel.

Обе библиотеки могут использоваться для динамического чтения, записи и изменения содержимого электронной таблицы Excel и обеспечивают эффективный способ интеграции Microsoft Excel в приложение Java.

Зависимости Maven

Для начала нужно добавить следующие зависимости в файл pom.xml:

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>5.2.0</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>5.2.0</version>
</dependency>

Последние версии poi-ooxml и jxls-jexcel можно загрузить с Maven Central.

Apache POI

Библиотека Apache POI поддерживает файлы .xls и .xlsx и является более сложной библиотекой, чем другие библиотеки Java для работы с файлами Excel.

Она предоставляет интерфейс Workbook для моделирования файла Excel и интерфейсы Sheet, Row и Cell, которые моделируют элементы файла Excel, а также реализации каждого интерфейса для обоих форматов файлов.

При работе с более новым форматом файлов .xlsx будем использовать классы XSSFWorkbook, XSSFSheet, XSSFRow и XSSFCell. Для работы со старым форматом .xls используем классы HSSFWorkbook, HSSFSheet, HSSFRow и HSSFCell.

Чтение из Excel

Создадим метод, который открывает файл .xlsx, а затем считывает содержимое с первого листа файла.

Метод чтения содержимого ячейки зависит от типа данных в ячейке. Тип содержимого ячейки можно определить с помощью метода getCellType() интерфейса Cell.

Во-первых, откроем файл из заданного места:

FileInputStream file = new FileInputStream(new File(fileLocation));
Workbook workbook = new XSSFWorkbook(file);

Затем извлечем первый лист файла и пройдемся по каждой строке:

Sheet sheet = workbook.getSheetAt(0);

Map<Integer, List<String>> data = new HashMap<>();
int i = 0;
for (Row row : sheet) {
    data.put(i, new ArrayList<String>());
    for (Cell cell : row) {
        switch (cell.getCellType()) {
            case STRING: ... break;
            case NUMERIC: ... break;
            case BOOLEAN: ... break;
            case FORMULA: ... break;
            default: data.get(new Integer(i)).add(" ");
        }
    }
    i++;
}

Apache POI имеет разные методы чтения каждого типа данных. Расширим содержание каждого случая переключателя выше.

Если значением перечисления типа ячейки является STRING, содержимое будет считываться с использованием метода getRichStringCellValue() интерфейса Cell:

data.get(new Integer(i)).add(cell.getRichStringCellValue().getString());

Ячейки с типом содержимого NUMERIC могут содержать дату или число и считываются следующим образом:

if (DateUtil.isCellDateFormatted(cell)) {
    data.get(i).add(cell.getDateCellValue() + "");
} else {
    data.get(i).add(cell.getNumericCellValue() + "");
}

Для логических значений есть метод getBooleanCellValue():

data.get(i).add(cell.getBooleanCellValue() + "");

Если тип ячейки FORMULA, можно использовать метод getCellFormula():

data.get(i).add(cell.getCellFormula() + "");

Запись в Excel

Apache POI использует те же интерфейсы, что и в предыдущем разделе, для записи в файл Excel и имеет лучшую поддержку стилей, чем JExcel.

Создадим метод, который записывает список людей на лист под названием «Persons».

Во-первых, создадим и настроим строку заголовка, содержащую ячейки «Name» и «Age»:

Workbook workbook = new XSSFWorkbook();

Sheet sheet = workbook.createSheet("Persons");
sheet.setColumnWidth(0, 6000);
sheet.setColumnWidth(1, 4000);

Row header = sheet.createRow(0);

CellStyle headerStyle = workbook.createCellStyle();
headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex());
headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);

XSSFFont font = ((XSSFWorkbook) workbook).createFont();
font.setFontName("Arial");
font.setFontHeightInPoints((short) 16);
font.setBold(true);
headerStyle.setFont(font);

Cell headerCell = header.createCell(0);
headerCell.setCellValue("Name");
headerCell.setCellStyle(headerStyle);

headerCell = header.createCell(1);
headerCell.setCellValue("Age");
headerCell.setCellStyle(headerStyle);

Далее напишем содержимое таблицы другим стилем:

CellStyle style = workbook.createCellStyle();
style.setWrapText(true);

Row row = sheet.createRow(2);
Cell cell = row.createCell(0);
cell.setCellValue("John Smith");
cell.setCellStyle(style);

cell = row.createCell(1);
cell.setCellValue(20);
cell.setCellStyle(style);

Наконец, запишем содержимое в файл «temp.xlsx» в текущем каталоге и закроем книгу:

File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + "temp.xlsx";

FileOutputStream outputStream = new FileOutputStream(fileLocation);
workbook.write(outputStream);
workbook.close();

Проверим вышеуказанные методы в тесте JUnit, который записывает содержимое в файл temp.xlsx, а затем читает тот же файл, чтобы убедиться, что он содержит написанный нами текст:

public class ExcelTest {

    private ExcelPOIHelper excelPOIHelper;
    private static String FILE_NAME = "temp.xlsx";
    private String fileLocation;

    @Before
    public void generateExcelFile() throws IOException {
        File currDir = new File(".");
        String path = currDir.getAbsolutePath();
        fileLocation = path.substring(0, path.length() - 1) + FILE_NAME;

        excelPOIHelper = new ExcelPOIHelper();
        excelPOIHelper.writeExcel();
    }

    @Test
    public void whenParsingPOIExcelFile_thenCorrect() throws IOException {
        Map<Integer, List<String>> data
          = excelPOIHelper.readExcel(fileLocation);

        assertEquals("Name", data.get(0).get(0));
        assertEquals("Age", data.get(0).get(1));

        assertEquals("John Smith", data.get(1).get(0));
        assertEquals("20", data.get(1).get(1));
    }
}

JExcel

Библиотека JExcel – это облегченная библиотека с тем преимуществом, что ее проще использовать, чем Apache POI, но с тем недостатком, что она поддерживает только обработку файлов Excel в формате .xls (1997–2003).

На данный момент файлы .xlsx не поддерживаются.

Чтение из Excel

Для работы с файлами Excel эта библиотека предоставляет ряд классов, представляющих различные части файла Excel. Класс Workbook представляет всю коллекцию листов. Класс Sheet представляет один лист, а класс Cell представляет одну ячейку электронной таблицы.

Напишем метод, который создает книгу из указанного файла Excel, получает первый лист файла, затем просматривает его содержимое и добавляет каждую строку в HashMap:

public class JExcelHelper {

    public Map<Integer, List<String>> readJExcel(String fileLocation) 
      throws IOException, BiffException {
 
        Map<Integer, List<String>> data = new HashMap<>();

        Workbook workbook = Workbook.getWorkbook(new File(fileLocation));
        Sheet sheet = workbook.getSheet(0);
        int rows = sheet.getRows();
        int columns = sheet.getColumns();

        for (int i = 0; i < rows; i++) {
            data.put(i, new ArrayList<String>());
            for (int j = 0; j < columns; j++) {
                data.get(i)
                  .add(sheet.getCell(j, i)
                  .getContents());
            }
        }
        return data;
    }
}

Запись в Excel

Для записи в файл Excel библиотека JExcel предлагает классы, аналогичные использованным выше, которые моделируют файл электронной таблицы: WritableWorkbook, WritableSheet и WritableCell.

Класс WritableCell имеет подклассы, соответствующие различным типам записываемого содержимого: Label, DateTime, Number, Boolean, Blank и Formula.

Эта библиотека также обеспечивает поддержку базового форматирования, такого как управление шрифтом, цветом и шириной ячейки.

Напишем метод, который создает книгу с именем «temp.xls» в текущем каталоге, а затем записывает то же содержимое, что и в разделе Apache POI.

Сначала создадим рабочую книгу:

File currDir = new File(".");
String path = currDir.getAbsolutePath();
String fileLocation = path.substring(0, path.length() - 1) + "temp.xls";

WritableWorkbook workbook = Workbook.createWorkbook(new File(fileLocation));

Далее создадим первый лист и напишем заголовок excel-файла, содержащего ячейки «Name» и «Age»:

WritableSheet sheet = workbook.createSheet("Sheet 1", 0);

WritableCellFormat headerFormat = new WritableCellFormat();
WritableFont font
  = new WritableFont(WritableFont.ARIAL, 16, WritableFont.BOLD);
headerFormat.setFont(font);
headerFormat.setBackground(Colour.LIGHT_BLUE);
headerFormat.setWrap(true);

Label headerLabel = new Label(0, 0, "Name", headerFormat);
sheet.setColumnView(0, 60);
sheet.addCell(headerLabel);

headerLabel = new Label(1, 0, "Age", headerFormat);
sheet.setColumnView(0, 40);
sheet.addCell(headerLabel);

В новом стиле напишем содержимое созданной таблицы:

WritableCellFormat cellFormat = new WritableCellFormat();
cellFormat.setWrap(true);

Label cellLabel = new Label(0, 2, "John Smith", cellFormat);
sheet.addCell(cellLabel);
Number cellNumber = new Number(1, 2, 20, cellFormat);
sheet.addCell(cellNumber);

Очень важно не забыть записать в файл и закрыть его в конце, чтобы его могли использовать другие процессы, используя методы write() и close() класса Workbook:

workbook.write();
workbook.close();

Заключение

В этой статье показано, как использовать Apache POI API и JExcel API для чтения и записи файла Excel из программы Java.

Полный исходный код для этой статьи можно найти на GitHub.

Оригинал