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

java - 使用SXSSFWorkbook读取Excel,内存无法释放?

孔山
2024-01-22

使用SXSSFWorkbook读取Excel,1W行数据,188列(测试时只有前16列有数据)
读取操作完成后,JVM中存在大量的org.apache.xmlbeans.impl.store.Xobj$AttrXobj org.apache.xmlbeans.impl.store.Xobj$ElementXob类的实例,很长时间内不会被GC
image.png

@RestControllerpublic class Test4 {  @GetMapping("/hello")  public String hello() {    // 标题栏行数    int hDefine = 7;    // 有效数据列    int headerSize = 188;    // 最大读取行数    int maxDataRow = 10000;    // 行号列    int rowNumDefine = 2;    try (        XSSFWorkbook wb = new XSSFWorkbook("D:\\Test.xlsx");        SXSSFWorkbook swb = new SXSSFWorkbook(wb, 100);        XSSFWorkbook newXssfWorkbook = swb.getXSSFWorkbook()) {      Sheet sheet = newXssfWorkbook.getSheetAt(0);      DataFormatter formatterExcel = new DataFormatter();      int i;      int j;      Row row;      Cell cell;      boolean isEmptyRow;      for (i = hDefine; i < maxDataRow + hDefine; i++) {        row = sheet.getRow(i);        if (row == null) {          break;        }        isEmptyRow = true;        List<String> rowString = new ArrayList<>();        for (j = rowNumDefine; j < headerSize + rowNumDefine; j++) {          cell = row.getCell(j);          String stringValue = "";          if (cell != null && !isBlankOrNull(formatterExcel.formatCellValue(cell))) {            isEmptyRow = false;            String text = formatterExcel.formatCellValue(cell);            FontColor textColor = getCellTextColor(swb, cell);            String formatter = textColor.getHtmlFormatter();            stringValue = String.format(formatter, text);          }          rowString.add(stringValue);        }        if (isEmptyRow) {          break;        }        // 省略其他业务代码      }      swb.dispose();    } catch (EncryptedDocumentException | IOException e) {      throw new RuntimeException("导入时发生错误", e);    }    return "hello";  }  public static boolean isBlankOrNull(String str) {    return str == null || str.trim().isEmpty();  }  public static FontColor getCellTextColor(Workbook wk, Cell cell) {    FontColor textColor = FontColor.BLACK;    if (cell == null) {      return textColor;    }    CellStyle cellStyle = cell.getCellStyle();    Font font = wk.getFontAt(cellStyle.getFontIndexAsInt());    XSSFColor color = Optional.ofNullable(((XSSFFont) font).getXSSFColor())        .orElse(new XSSFColor(new java.awt.Color(0, 0, 0), new DefaultIndexedColorMap()));    byte[] rgb = color.getRGB();    textColor = FontColor.valueOf(rgb);    return textColor;  }  public enum FontColor {    BLACK, RED, BLUE;    public String getHtmlFormatter() {      switch (this) {        case BLACK:          return "%s";        case RED:          return "<span style=\"color: red;\">%s</span>";        case BLUE:          return "<span style=\"color: blue;\">%s</span>";      }      return "%s";    }    public static FontColor valueOf(byte[] rgb) {      FontColor ret = FontColor.BLACK;      int red = (rgb[0] < 0) ? (rgb[0] + 256) : rgb[0];      int green = (rgb[1] < 0) ? (rgb[1] + 256) : rgb[1];      int blue = (rgb[2] < 0) ? (rgb[2] + 256) : rgb[2];      if (red == 255 && green == 0 && blue == 0) {        ret = FontColor.RED;      } else if (red == 0 && green == 0 && blue == 255) {        ret = FontColor.BLUE;      }      return ret;    }  }}

我尝试过使用SAX事件驱动解析Excel、StreamingReader读取Excel。
但是实现过程中,都发现似乎并不能获取到单元格的字体的颜色样式(或者是我菜鸡没找到相应的方法)
(PS:客户的要求,单元格内给字体设置颜色,然后读取这个颜色样式进而生成html颜色样式,大雾....)

请问:
1.SAX事件驱动解析Excel、StreamingReader读取Excel是否可以获取到某个单元格的字体的颜色样式?
2.上述这种疑似内存泄漏的问题的原因是我代码的问题吗?

共有1个答案

龚远
2024-01-22
  1. 使用SAX事件驱动解析Excel或StreamingReader读取Excel时,可以获取到某个单元格的字体的颜色样式。在解析Excel的过程中,你可以访问单元格的字体属性,包括颜色样式。你需要使用相应的API来获取这些信息。在Apache POI库中,可以使用XSSFCellStyle和XSSFFont类来获取字体颜色样式。

对于SAX事件驱动解析Excel,你需要实现相应的处理器来处理Excel文档中的事件,并在事件处理过程中访问单元格的字体属性。以下是一个简单的示例代码片段,展示了如何使用SAX事件驱动解析Excel并获取字体颜色样式:

import org.apache.poi.ss.usermodel.*;import org.apache.poi.xssf.eventusermodel.XSSFReader;import org.xml.sax.Attributes;import org.xml.sax.SAXException;import org.xml.sax.helpers.DefaultHandler;public class ExcelHandler extends DefaultHandler {    private CellStyle cellStyle;    private Font font;    private String color;    @Override    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {        if ("ss:Cell".equals(qName)) {            cellStyle = null;        } else if ("ss:Font".equals(qName)) {            font = null;        } else if ("ss:Color".equals(qName)) {            color = attributes.getValue("val");        }    }    @Override    public void endElement(String uri, String localName, String qName) throws SAXException {        if ("ss:Cell".equals(qName)) {            // 处理单元格数据和样式        } else if ("ss:Font".equals(qName)) {            if (font != null && color != null) {                // 设置字体颜色样式            }        } else if ("ss:Color".equals(qName)) {            color = null;        }    }    @Override    public void characters(char[] ch, int start, int length) throws SAXException {        if (font != null && color != null) {            int red = Integer.parseInt(color.substring(1, 3), 16);            int green = Integer.parseInt(color.substring(3, 5), 16);            int blue = Integer.parseInt(color.substring(5, 7), 16);            font.setColor(new java.awt.Color(red, green, blue));        }    }}

在上面的代码中,我们使用SAX事件驱动解析Excel文档,并在startElementendElement方法中跟踪单元格、字体和颜色的开始和结束标签。在characters方法中,我们根据字体和颜色标签的内容设置字体颜色样式。请注意,这只是一个简单的示例,实际使用时可能需要根据具体情况进行适当的修改。

  1. 对于你提到的疑似内存泄漏问题,它可能是由于某些对象在使用后没有被正确释放或回收所致。在你的代码中,你使用了SXSSFWorkbook来读取Excel文件,它是一个基于流的Workbook实现,用于处理大型Excel文件。通常情况下,SXSSFWorkbook会自动管理内存的释放和回收。然而,如果你在处理过程中创建了大量的临时对象或持有大量数据,可能会导致内存占用过高。为了解决这个问题,你可以尝试以下几个方法:
  2. 确保及时释放不再需要的资源,例如关闭流、释放数据库连接等。这有助于减少内存占用。
  3. 使用适当的缓存策略,避免重复创建相同的对象或数据结构。你可以使用Java的缓存框架(如Ehcache、Guava Cache等)来管理缓存。
  4. 考虑使用更高效的数据结构或算法来处理数据。例如,如果你需要存储大量数据,可以考虑使用集合类(如List、Set)或自定义的数据结构来优化内存占用。
 类似资料:
  • 但是电子表格表示已更改的元数据,并且当元数据已更改时,我希望在显示旧值的单元格中添加注释。我在小的电子表格上使用了这个方法,但是当尝试处理大文件时,它总是失败,导致堆内存错误。 我不确定问题是由于Poi限制将所有注释存储在内存中,还是我做错了。Worksheet是我自己的包装类,我只为每个sheet创建一个DrawingPatriach类,但看起来我必须为我需要的每个注释创建一个锚。

  • 问题内容: 我试图在共享内存上发布一些随机的东西;出于某些奇怪的原因,阅读器没有选择发件人写的东西 这是发件人: 这是读者: 如果重新启动阅读器,则阅读器确实能够读取发送方已写入的最后一个值。 但是,如果我先启动阅读器,然后再启动发送器,则阅读器不会拾取发送器写入的所有值。 为了使这个更奇怪,如果我在SHM :: read()中取消对printf语句的注释,那么读者有时可以使用。 任何的想法? G

  • 我使用apache poi for Excel2007使用XSSF时遇到了问题 有什么想法吗?我是否应该移动行,或者移除行,或者两者的组合? 编辑:实际上,第一个片段也引起了一个问题...有时????我觉得我做错了什么...有什么建议吗?

  • Apache POI>无法读取Excel表 null } Excel文件

  • 有几个相关的问题,但我找不到一个能反映我的情况的。 我正在使用SXSSFWorkbook和SXSSFSheet对象编写一个带有ApachePOI的Excel“xlsx”文件。文件创建时没有问题,在LibreOffice中可以正常打开,但是Excel在打开文件时会发出抱怨。 Excel在test-file.xlsx中发现无法读取的内容。要恢复工作簿的内容吗?如果信任此工作簿的源,请单击是。 当选择“

  • 本文向大家介绍Java用jxl读取excel并保存到数据库的方法,包括了Java用jxl读取excel并保存到数据库的方法的使用技巧和注意事项,需要的朋友参考一下 项目中涉及到读取excel中的数据,保存到数据库中,用jxl做起来比较简单。 基本的思路: 把excel放到固定盘里,然后前段页面选择文件,把文件的名字传到后台,再利用jxl进行数据读取,把读取到的数据存到list中,通过遍历list,