копировать ячейки между книгами Excel с Apache POI - PullRequest
2 голосов
/ 18 марта 2020

Я пытаюсь скопировать из ячеек из одной книги в другую последнюю версию Apache POI (4.1.2).

Если обе книги представляют собой файлы .xlsx, все работает нормально. Но если исходная рабочая книга - это (старый) файл .xls, а конечная рабочая книга - файл .xlsx, следующий код завершится ошибкой

// Copy style from old cell and apply to new cell
CellStyle newCellStyle = targetWorkbook.createCellStyle();
newCellStyle.cloneStyleFrom(sourceCell.getCellStyle());
targetCell.setCellStyle(newCellStyle);

Исключение, которое выдается:

java .lang.IllegalArgumentException: может клонировать только из одного XSSFCellStyle в другой, а не между HSSFCellStyle и XSSFCellStyle

Если мы не можем использовать cloneStyleFrom, когда файлы (или Workbook объекты) ) разных типов, как мы можем преобразовать HSSFCellStyle объект в XSSFCellStyle?

1 Ответ

4 голосов
/ 19 марта 2020

Ответ на ваш вопрос "Как мы можем преобразовать HSSFCellStyle объект в XSSFCellStyle?" является: Мы не можем сделать это, используя apache poi 4.1.2. Это просто не поддерживается, как четко указано в CellStyle.cloneStyleFrom : «Однако оба типа CellStyles должны быть одного типа (HSSFCellStyle или XSSFCellStyle).»

Другой вопрос это: Если мы вообще конвертируем один стиль ячейки в другой? Или какие варианты использования вообще существуют для CellStyle.cloneStyleFrom? На мой взгляд их нет. Существуют Excel ограничения на количество уникальных форматов ячеек / стилей ячеек. См. Спецификации и ограничения Excel . Поэтому мы не должны создавать единый стиль ячейки для каждой отдельной ячейки, потому что тогда эти ограничения будут достигнуты очень быстро. Таким образом, вместо клонирования стилей ячеек мы должны получить свойства стиля из исходного стиля style1 и затем использовать CellUtil.setCellStyleProperties , чтобы установить эти свойства стиля для другой рассматриваемой ячейки. Этот метод пытается найти существующий CellStyle, который соответствует текущему стилю плюс свойства стиля в properties. Новый стиль создается только в том случае, если книга не содержит соответствующего стиля.

Поскольку ваш вопрос называется «Копировать ячейки между книгами Excel с Apache POI», я создал рабочий черновик того, как я сделайте это.

Следующий код сначала получает существующий Workbook.xls как HSSFWorkbook wb1 и создает новый XSSFWorkbook wb2. Затем он перебирает все ячейки первого листа wb1 и пытается скопировать эти ячейки на первый лист wb2. Для этого есть метод copyCells(Cell cell1, Cell cell2), который использует copyStyles(Cell cell1, Cell cell2). Последний получает свойства стиля из исходного стиля style1, полученного из cell1, а затем использует CellUtil.setCellStyleProperties, чтобы установить для этих свойств стиля значение cell2. Для копирования используются шрифты copyFont(Font font1, Workbook wb2). Это попытается создать новые шрифты в wb2, только если такого шрифта еще нет в этой книге. Это необходимо, поскольку в каждой рабочей книге есть ограничение на количество уникальных типов шрифтов в Excel.

Рабочий пример:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.util.CellUtil;

import java.io.FileInputStream;
import java.io.FileOutputStream;

import java.util.*;

class ExcelCopyCells {

 static Font copyFont(Font font1, Workbook wb2) {
  boolean isBold = font1.getBold();
  short color = font1.getColor();
  short fontHeight = font1.getFontHeight();
  String fontName = font1.getFontName();
  boolean isItalic = font1.getItalic();
  boolean isStrikeout = font1.getStrikeout();
  short typeOffset = font1.getTypeOffset();
  byte underline = font1.getUnderline();

  Font font2 = wb2.findFont(isBold, color, fontHeight, fontName, isItalic, isStrikeout, typeOffset, underline);
  if (font2 == null) {
   font2 = wb2.createFont();
   font2.setBold(isBold);
   font2.setColor(color);
   font2.setFontHeight(fontHeight);
   font2.setFontName(fontName);
   font2.setItalic(isItalic);
   font2.setStrikeout(isStrikeout);
   font2.setTypeOffset(typeOffset);
   font2.setUnderline(underline);
  }

  return font2;
 }

 static void copyStyles(Cell cell1, Cell cell2) {
  CellStyle style1 = cell1.getCellStyle();
  Map<String, Object> properties = new HashMap<String, Object>();

  //CellUtil.DATA_FORMAT
  short dataFormat1 = style1.getDataFormat();
  if (BuiltinFormats.getBuiltinFormat(dataFormat1) == null) {
   String formatString1 = style1.getDataFormatString();
   DataFormat format2 = cell2.getSheet().getWorkbook().createDataFormat();
   dataFormat1 = format2.getFormat(formatString1);
  }
  properties.put(CellUtil.DATA_FORMAT, dataFormat1);

  //CellUtil.FILL_PATTERN  
  //CellUtil.FILL_FOREGROUND_COLOR 
  FillPatternType fillPattern = style1.getFillPattern();
  short fillForegroundColor = style1.getFillForegroundColor(); //gets only indexed colors, no custom HSSF or XSSF colors
  properties.put(CellUtil.FILL_PATTERN, fillPattern);
  properties.put(CellUtil.FILL_FOREGROUND_COLOR, fillForegroundColor);

  //CellUtil.FONT
  Font font1 = cell1.getSheet().getWorkbook().getFontAt(style1.getFontIndexAsInt());
  Font font2 = copyFont(font1, cell2.getSheet().getWorkbook());
  properties.put(CellUtil.FONT, font2.getIndexAsInt());

  //BORDERS
  BorderStyle borderStyle = null;
  short borderColor = -1;
  //CellUtil.BORDER_LEFT 
  //CellUtil.LEFT_BORDER_COLOR
  borderStyle = style1.getBorderLeft();
  properties.put(CellUtil.BORDER_LEFT, borderStyle);
  borderColor = style1.getLeftBorderColor();
  properties.put(CellUtil.LEFT_BORDER_COLOR, borderColor);
  //CellUtil.BORDER_RIGHT 
  //CellUtil.RIGHT_BORDER_COLOR
  borderStyle = style1.getBorderRight();
  properties.put(CellUtil.BORDER_RIGHT, borderStyle);
  borderColor = style1.getRightBorderColor();
  properties.put(CellUtil.RIGHT_BORDER_COLOR, borderColor);
  //CellUtil.BORDER_TOP 
  //CellUtil.TOP_BORDER_COLOR
  borderStyle = style1.getBorderTop();
  properties.put(CellUtil.BORDER_TOP, borderStyle);
  borderColor = style1.getTopBorderColor();
  properties.put(CellUtil.TOP_BORDER_COLOR, borderColor);
  //CellUtil.BORDER_BOTTOM 
  //CellUtil.BOTTOM_BORDER_COLOR
  borderStyle = style1.getBorderBottom();
  properties.put(CellUtil.BORDER_BOTTOM, borderStyle);
  borderColor = style1.getBottomBorderColor();
  properties.put(CellUtil.BOTTOM_BORDER_COLOR, borderColor);

  CellUtil.setCellStyleProperties(cell2, properties);
 }

 static void copyCells(Cell cell1, Cell cell2) {
  switch (cell1.getCellType()) {
   case STRING:
   /*
    //TODO: copy HSSFRichTextString to XSSFRichTextString 
    RichTextString rtString1 = cell1.getRichStringCellValue();
    cell2.setCellValue(rtString1); // this fails if cell2 is XSSF and rtString1 is HSSF
   */
    String string1 = cell1.getStringCellValue();
    cell2.setCellValue(string1);
   break;
   case NUMERIC:
    if (DateUtil.isCellDateFormatted(cell1)) {
     Date date1 = cell1.getDateCellValue();
     cell2.setCellValue(date1);
    } else {
     double cellValue1 = cell1.getNumericCellValue();
     cell2.setCellValue(cellValue1);
    }
   break;
   case FORMULA:
    String formula1 = cell1.getCellFormula();
    cell2.setCellFormula(formula1);
   break;

   //case : //TODO: further cell types

  }

  copyStyles(cell1, cell2);

 }

 public static void main(String[] args) throws Exception {
  Workbook wb1 = WorkbookFactory.create(new FileInputStream("Workbook.xls"));
  Workbook wb2 = new XSSFWorkbook();

  Sheet sheet1 = wb1.getSheetAt(0);
  Sheet sheet2 = wb2.createSheet();

  Set<Integer> columns = new HashSet<Integer>();
  Row row2 = null;
  Cell cell2 = null;
  for (Row row1 : sheet1) {
   row2 = sheet2.createRow(row1.getRowNum());
   for (Cell cell1 : row1) {
    columns.add(cell1.getColumnIndex());
    cell2 = row2.createCell(cell1.getColumnIndex());
    copyCells(cell1, cell2);
   }
  }

  wb1.close();

  for (Integer column : columns) {
   sheet2.autoSizeColumn(column);
  }

  FileOutputStream out = new FileOutputStream("Workbook.xlsx");
  wb2.write(out);
  out.close();
  wb2.close();
 }
}

Если Workbook.xls выглядит следующим образом:

enter image description here

, тогда результирующее Workbook.xlsx выглядит так:

enter image description here

Примечание: Это рабочий проект и должен быть завершен. См. TODO комментарии в коде. RichTextString значения ячеек необходимо учитывать. Другие типы клеток должны быть рассмотрены.

Метод copyStyles обеспечивает только копирование формата данных, заливки рисунка и заливки основного цвета (только для индексированных цветов), шрифта и границ. Дополнительные свойства стиля ячейки должны быть рассмотрены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...