使用 Apache POI 从 Excel 到 Java 的空白单元格中读取颜色

Read a Color from a Blank Cell in Excel to Java using Apache POI

背景:我正在尝试将 Excel 文件读入 Java 程序。 我的 Excel 文件用于表示网格或栅格地图,因此我将每个单元格的高度和宽度设为一英寸。这个想法是,我可以通过在每个单元格中用一种颜色着色来 "draw" 一张地图或图像。然后,我可以将 Excel 文件读取到我自己用 "Pixel" 对象创建的 Java 程序,并创建一个更真实的图像。 我是计算机科学专业的本科生,此时我只有四个计算机科学 class。我了解 OOP 并且可以在 Java 中编程。这不是 class;这是一个副项目。我正在使用 XSSF(Microsoft 2007 及之后的版本)。

RESEARCH:我发现解决这个问题的方法是使用 Apache POI。我已经下载了所需的 Apache POI jar 文件并在 Eclipse 中配置了 BuildPath 以读取它们。我发现使用 Iterator hasNext() 方法会跳过空白单元格,因此解决方案是使用更直接的 getCell() 方法。我发现有两种 getCell() 方法——一种仅将索引作为输入,另一种同时使用索引输入和 MissingCellPolicy。但是,当我尝试通过将 RETURN_NULL_AND_BLANK 作为输入来使用 MissingCellPolicy 方法时,它使单元格变为空白,但在此过程中使颜色变为空。 MissingCellPolicy CREATE_NULL_AS_BLANK 有同样的问题。

一个低效的解决方案:当我将文本放入单元格时,它会正确读取颜色。即使是迭代器方法也可以正确读取其中包含文本的单元格。这是因为一旦我将文本放入其中,单元格就会被初始化。但是,我尝试创建的网格太大,无法在每个单元格中放置文本。可能有一种方法可以将 sheet 上的每个单元格设置为具有相同的文本,但我也不能这样做,因为我的网格中已经有许多单元格具有特定文本,并且无法删除它们.这也可能使所有单元格都具有相同的颜色,我现在也做不到。此外,如果我可以有没有文本的单元格,我会更喜欢它。

TL;DR:我需要使用 Apache POI 将 Excel 中单元格的颜色读入 Java,而无需将文本写入单元格.根据我的理解,带有 MissingCellPolicy 的方法 getCell() 不起作用,因为该策略创建了一个新的空白单元格,覆盖了现有的颜色。我在 Apache POI 中看到了很多关于读取空白单元格的问题,但是我没有看到关于访问颜色的问题。

MAIN CODE:

    try {
        FileInputStream file = new FileInputStream(new File("My FilePath"));
        XSSFWorkbook workbook = new XSSFWorkbook(file);
        XSSFSheet sheet = workbook.getSheetAt(0);
        for(int i=0; i<5040; i++) {
            Row row = sheet.getRow(i);
        for(int j=0; j<10080; j++) {
            Cell cell = row.getCell(j, Row.MissingCellPolicy.RETURN_NULL_AND_BLANK);
            ExtendedColor color = (ExtendedColor) cell.getCellStyle().getFillForegroundColorColor(); 
            //NOTE: getFillBackgroundColorColor did not work! It only returns the color black.
            byte[] bytes = color.getRGB();
            RGBColor rgb = new RGBColor(bytes);
            String text = cell.getStringCellValue();
            Coordinate coordinate = new Coordinate(j, i);
            Tile tile = new Tile(rgb, text);
            map[j][i] = tile;
            // Coordinate and Tile are other objects I made myself. 
            // The map is a two-dimensional array of Tiles, declared previously. 
            // I left this code here because it works.
        }
    }
    workbook.close();
    file.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

RGBColor构造函数代码:

    public RGBColor(byte[] bytes) {
        if(bytes != null) {
        this.red = (int) bytes[0];
        this.green = (int) bytes[1];
        this.blue = (int) bytes[2];
        if(red<0) {red = red+256;}
        if(green<0) {green = green+256;}
        if(blue<0) {blue = blue+256;}
    }

RESULT: 如果单元格中有文本,上面的代码会正确读取单元格的颜色,并根据该颜色创建 RGBColor 对象。上面的代码还可以从单元格中读取文本。但是,一旦到达没有文本的单元格,它就会在 ExtendedColor 行处导致 NullPointerException(因此该单元格为空)。当使用 MissingCellPolicy CREATE_NULL_AS_BLANK 时,它会在 byte[] 行导致 NullPointerException(因此颜色为空)。感谢任何帮助,即使它不是我所要求的,因为我是 Apache POI!

的新手

最终发生的事情是您尝试处理空单元格或空白单元格,而不是在遇到它们时进行处理。在调用 getCell():

之后你想要做的是这样的
if (cell == null || cell.getCellType() == Cell.CELL_TYPE_BLANK) {
    // assign whatever color you want for a blank cell to rgb
} else {
    // do your logic to get the ExtendedColor and turn it into an RGBColor
}

单个 彩色单元格永远不能为空。它必须存在。所以我们只能遍历现有的单元格。 CellStyle 根据定义不为空。但是如果没有颜色,CellStyle.getFillForegroundColorColor 可以 return null。所以我们需要检查一下。

假设如下 sheet:

代码:

import org.apache.poi.ss.usermodel.*;
import java.io.*;

import java.util.Arrays;

class ReadColorsFromExcel {

 public static void main(String[] args) throws Exception{

  InputStream inp = new FileInputStream("MyFile.xlsx");
  Workbook workbook = WorkbookFactory.create(inp);
  Sheet sheet = workbook.getSheetAt(0);
  for (Row row : sheet) {
   for (Cell cell : row) { // cell will always be not-null only existing cells are in loop
    CellStyle cellStyle = cell.getCellStyle(); // cellStyle is always not-null
    ExtendedColor extendedColor = (ExtendedColor)cellStyle.getFillForegroundColorColor(); // extendedColor may be null
    String color = "none";
    if (extendedColor != null) {
     byte[] bytes = extendedColor.getRGB();
     color = Arrays.toString(bytes);
    }
    System.out.println("Cell " + cell.getAddress() + " of type " + cell.getCellType() + " has color " + color);
   }
  }
 }
}

将打印:

Cell A1 of type 1 has color none
Cell B1 of type 0 has color [-1, -1, 0]
Cell C1 of type 2 has color none
Cell B3 of type 0 has color none
Cell C3 of type 3 has color [-110, -48, 80]
Cell D4 of type 1 has color none
Cell B6 of type 3 has color [0, 112, -64]
Cell D7 of type 3 has color [-1, 0, 0]
Cell A9 of type 3 has color [-1, -64, 0]
Cell F12 of type 3 has color [0, -80, 80]

但在 Excel 中,整列和整行也可能有样式。如果是这样,不是单元格将具有颜色,而是列 and/or 行。因此,如果还需要获取不存在的单元格,例如当前未存储的单元格,因此为空,并且还考虑到可能存在列样式(整列)和行样式(整行),然后考虑以下内容:

Sheet:

所有单元格(所有列)的背景为白色,第 8 行为浅蓝色背景,E 列为浅绿色背景。有些细胞有自己的细胞背景。

代码:

import org.apache.poi.ss.usermodel.*;
import java.io.*;

import java.util.Arrays;

class ReadColorsFromExcel {

 public static void main(String[] args) throws Exception{

  InputStream inp = new FileInputStream("MyFile.xlsx");
  Workbook workbook = WorkbookFactory.create(inp);
  Sheet sheet = workbook.getSheetAt(0);

  int lastRow = 12;
  int lastCol = 6;

  for (int rowNum = 0; rowNum < lastRow; rowNum++) {
   Row row = sheet.getRow(rowNum);
   if (row == null) {
    row = sheet.createRow(rowNum);
   }
   CellStyle rowStyle = row.getRowStyle(); // if the whole row has a style
   for (int colNum = 0; colNum < lastCol; colNum++) {
    CellStyle colStyle = sheet.getColumnStyle(colNum); // if the whole column has a style
    Cell cell = row.getCell(colNum, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK);
    CellStyle cellStyle = cell.getCellStyle(); // cellStyle is always not-null
    String color = "none";
    ExtendedColor extendedColor = (ExtendedColor)cellStyle.getFillForegroundColorColor(); // first we try cellStyle
    if (extendedColor == null && rowStyle != null) extendedColor = (ExtendedColor)rowStyle.getFillForegroundColorColor(); // now we try rowStyle
    if (extendedColor == null && colStyle != null) extendedColor = (ExtendedColor)colStyle.getFillForegroundColorColor(); // at last we try colStyle
    if (extendedColor != null) {
     byte[] bytes = extendedColor.getRGB();
     color = Arrays.toString(bytes);
    }
    System.out.println("Cell " + cell.getAddress() + " of type " + cell.getCellType() + " has color " + color);
   }
  }
 }
}

现在应该考虑所有可能的样式。