为了账号安全,请及时绑定邮箱和手机立即绑定

当使用 SXSSFWorkbook 创建 excel 并使用 XSSFWorkbook 修改

当使用 SXSSFWorkbook 创建 excel 并使用 XSSFWorkbook 修改

POPMUISE 2022-12-21 14:35:00
场景:1) 使用 SXSSFWorkbook 将一个 csv 文件转换为 excel 文件。2) 如果再次从 CSV 文件读取数据并使用 XSSFWorkbook 将数据写入上面生成的 excel 文件,则字符串数据在 libre office 中不可见,但如果在在线 excel 查看器中打开 excel 文件(一些 excel观众提到文件已损坏,数据可以恢复)。使用 SXSSFWorkbook 创建单元格:Cell cell = row.createCell(1);cell.setCellValue("一些值");使用 XSSFWorkbook 更新单元格:Cell cell = row.getCell(1);cell.setCellValue("一些值");观察结果:1) 当使用 XSSFCell 更新单元格值时,单元格的原始值和单元格的字符串值不同。2)如果excel文件是用SXSSFWorkbook生成的,用XSSFWorkbook打开的,那么内部维护的STCellType是STCellType.INLINE_STR,如果excel文件是用XSSFWorkbook生成的,那么内部维护的STCellType是STCellType.S(XSSFCell的CTCell中用的是STCellType)。Apache POI 版本:4.1.0请提出解决方案。
查看完整描述

1 回答

?
千巷猫影

TA贡献1829条经验 获得超7个赞

默认情况下SXSSFWorkbook使用内联字符串,而默认情况下XSSFWorkbook使用共享字符串表。并且XSSFCell.setCellValueImpl对于内联字符串是不完整的。它确实:


...

if(_cell.getT() == STCellType.INLINE_STR) {

 //set the 'pre-evaluated result

 _cell.setV(str.getString());

}

...

所以对于内联字符串,它总是设置v包含文本的元素。但是内联字符串也可能包含包含文本的is元素t,甚至包含is不同富文本运行的元素。这不被视为使用XSSFCell.


但是可以构建SXSSFWorkbook ,因此它也使用共享字符串表。请参阅构造函数SXSSFWorkbook(XSSFWorkbook workbook, int rowAccessWindowSize, boolean compressTmpFiles, boolean useSharedStringsTable)。因此,如果使用以下构造函数:


SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);

然后不使用内联字符串,以后使用更新XSSF也不会有问题。


如果SXSSFWorkbook不是使用shared strings table而是使用inline strings,由于in using inline stringsXSSF的不完整,后面更新cells using时会出现问题。XSSFCell可能的解决方法是管理使用自己的代码更新的内联字符串。


例子:


import java.io.FileOutputStream;

import java.io.FileInputStream;


import org.apache.poi.ss.usermodel.WorkbookFactory;

import org.apache.poi.xssf.usermodel.*;

import org.apache.poi.xssf.streaming.*;


import org.openxmlformats.schemas.spreadsheetml.x2006.main.STCellType;


public class SXSSFTest {


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


  // first create SXSSFTest.xlsx using SXSSF ============================================


  String[][] data1 = new String[][]{

   new String[]{"A1", "B1", "C1"},

   new String[]{"A2", "B2", "C2"},

   new String[]{"A3", "B3", "C3"},

   new String[]{"A4", "B4", "C4"}

  };


  SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook();

  //SXSSFWorkbook sxssfWorkbook = new SXSSFWorkbook(new XSSFWorkbook(), 2, true, true);


  SXSSFSheet sxssfSheet = sxssfWorkbook.createSheet();


  int r = 0;

  for (String[] rowValues : data1) {

   SXSSFRow row = sxssfSheet.createRow(r++);

   int c = 0;

   for (String value : rowValues) {

    SXSSFCell cell = row.createCell(c++);

    cell.setCellValue(value);

   }

  }


  FileOutputStream outputStream = new FileOutputStream("SXSSFTest.xlsx");

  sxssfWorkbook.write(outputStream);

  outputStream.close();

  sxssfWorkbook.dispose();

  sxssfWorkbook.close();


  // now reread the SXSSFTest.xlsx and update it using XSSF =============================


  String[][] data2 = new String[][]{

   new String[]{"A2 New", "B2 New", "C2 New"},

   new String[]{"A3 New", "B3 New", "C3 New"}

  };


  XSSFWorkbook xssfWorkbook = (XSSFWorkbook)WorkbookFactory.create(

                               new FileInputStream("SXSSFTest.xlsx"));


  XSSFSheet xssfSheet = xssfWorkbook.getSheetAt(0);


  r = 1;

  for (String[] rowValues : data2) {

   XSSFRow row = xssfSheet.getRow(r++); if (row == null) row = xssfSheet.createRow(r++);

   int c = 0;

   for (String value : rowValues) {

    XSSFCell cell = row.getCell(c++); 

    if (cell != null) { // cell was already there

     if (cell.getCTCell().getT() == STCellType.INLINE_STR) { // cell has inline string in it

      if (cell.getCTCell().isSetIs()) { // inline string has is element

       cell.getCTCell().getIs().setT(value); // set t element in is element

      } else {

       cell.getCTCell().setV(value); // set v element of inline string

      }

     } else {

      cell.setCellValue(value); // set shared string cell value

     }

    } else {

     cell = row.createCell(c++);

     cell.setCellValue(value);

    }

   }

  }


  outputStream = new FileOutputStream("XSSFTest.xlsx");

  xssfWorkbook.write(outputStream);

  outputStream.close();   

  xssfWorkbook.close();


 }

}

在那之后SXSSFTest.xlsx我的看起来像这样LibreOffice Calc:

//img1.sycdn.imooc.com//63a2a96a0001b1cc06560276.jpg

所有单元格中都有内联字符串。

XSSFTest.xlsx看起来像这样:

//img1.sycdn.imooc.com//63a2a9760001075706550273.jpg

现在所有内联字符串都已正确更新。


LibreOffice

Version: 6.0.7.3

Build ID: 1:6.0.7-0ubuntu0.18.04.5


查看完整回答
反对 回复 2022-12-21
  • 1 回答
  • 0 关注
  • 943 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信