当前位置: 首页 > 知识库问答 >
问题:

使用Apache POI在Excel工作簿之间复制单元格

郝修为
2023-03-14

我正在尝试使用最新版本的ApachePOI(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,如何将HSSFCellStyle对象转换为XSSFCellStyle

共有1个答案

长孙哲
2023-03-14

您的问题“如何将HSSFCellStyle对象转换为XSSFCellStyle?”的答案是:我们不能使用apache poi 4.1.2实现这一点。正如CellStyle.cloneStyleFrom中明确指出的那样,这根本不受支持:“但是,两种CellStyle都需要具有相同的类型(HSSFCellStyle或XSSFCellStyle)。”

另一个问题是:我们是否应该将一种单元格样式转换成另一种?或者有什么用例为CellStyle.clone样式在所有?在我看来没有。对于唯一单元格格式/单元格样式的计数存在Excel限制。请参见Excel规范和限制。因此,我们不应该为每个单元格创建单个单元格样式,因为这样会很快达到这些限制。因此,我们不应该克隆单元格样式,而是应该从源代码样式Style le1中获取样式属性,然后使用CellUtil.setCellStyleProperties将这些样式属性设置为其他有问题的单元格。此方法试图找到一个现有的CellStyle,该属性中匹配单元格的当前样式和样式属性。只有当工作簿不包含匹配的样式时,才会创建新样式。

因为您的问题标题是“使用ApachePOI在Excel工作簿之间复制单元格”,所以我已经创建了一个工作草案,说明了我将如何做到这一点。

下面的代码首先将现有的工作簿.xls作为HSSFWorkbookwb1获取,并创建一个新的XSSFWorkbookwb2。然后,它在wb1的第一页的所有单元格上循环,并尝试将这些单元格复制到wb2的第一页。为此,有一种方法copyCells(Cell-cell1,Cell-cell2),它使用复制样式(Cell-cell1,Cell-cell2)。后者从cell1获得的源样式style1中获取样式属性,然后使用CellUtil.setCellStyleProperties将这些样式属性设置为cell2。用于复制字体copyFont(Font font1,工作簿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如下所示:

然后生成的Workbook.xlsx如下所示:

注:这是一份工作草案,需要完成。请参见代码中的TODO注释<需要考虑代码>RichTextString单元格值。需要考虑更多的单元类型。

方法copyStyles仅提供复制数据格式、填充图案和填充前景色(仅用于索引颜色)、字体和边框。需要考虑更多的单元样式属性。

 类似资料:
  • 问题内容: 如何在Apache poi的两个不同的工作簿之间复制工作表? 该方法缺少引用此线程。没有这样的解决方案。 问题答案: 经过研究和尝试,这里是我的解决方案。我已经通过Java 1.6和apache-poi 3.8进行了测试 在这里,我将不提供适用于我的解决方案,特别是在这种情况下,我将粘贴工作表和输入流列表(我要合并的不同工作簿)。 我的解决方案是一个合并的解决方案,我从这里合并了整个源

  • 所以在问这个之前,我搜索并发现了一些与我在这里想要做的相似的事情。 基本上我有工作簿AlphaMaster。这个工作簿是一个模板,我想用它来创建每周的新工作簿。 在本工作簿中,有名为“周一至周六”的工作表,以及带有相应日期的周一、周二等其他工作表。 我创建了一个在打开工作簿时加载的表单。我想要的是当我单击表单运行时,它将: > 将代码保存模板作为新工作簿运行 根据userform1的输入重命名工作

  • 当在列中单击文本“发送调查”时,我正在尝试从工作表“”上的活动行复制单元格b中的值,并将其粘贴到单元格中。A2在我的另一个工作簿“”上的“”表。 由于某种原因,我没有收到任何错误,但是没有任何内容被粘贴到我的其他工作簿的单元格A2中。 有人能告诉我哪里出了问题吗。提前感谢

  • 请在下面找到代码片段 当我们创建excel文件时,这意味着我们正在创建工作簿。从那里,我们访问表格,然后是行和列。 我不明白为什么我们写写当我们已经有一个'Workbook'我们应该有一些方法来获取我们已经创建的工作簿,就像我们为行(getRow),工作表(getSheet),细胞(getcell)所做的那样。 你能帮我理解POI吗?

  • 我有一段巧妙的代码,它根据指定单元格中的特定文本输入隐藏/隐藏表。在Book1中的Sheet1中(比方说),如果我改变单元格A1中的文本(比方说文本是苹果、橘子等),我会在同一本书中的sheet2上得到某些表格(让我们称之为答题卡)。 现在,在另一本书中,我有一个表,其中包含所有可能的文本值(Apple,oranges,等等)。我想写一个代码,首先通过这个表,使值在book1.sheet1(“sh