Java Apache POI 错误
Java Apache POI Bug
在使用 Apache POI 实现时,我 运行 陷入了 st运行ge 行为。我无法解释原因,所以如果有人可以提供一些提示,我很乐意听取他们的意见。对于我正在解决的问题,它甚至不是一个大障碍——在这一点上,它更像是一件好奇的事情。所以这里是:
public static void main(String[] args) throws EcatException, SQLException, IOException, Exception {
long ts = System.currentTimeMillis();
SXSSFWorkbook wb = new SXSSFWorkbook();
SXSSFSheet test = wb.createSheet("Test");
SXSSFRow r = test.createRow(0);
Cell c = r.createCell(0);
c.setCellValue("TEST");
wb.write(new FileOutputStream("D:/wb-" + ts + ".xlsx"));
wb.close();
XSSFWorkbook wb2 = new XSSFWorkbook("D:/wb-" + ts + ".xlsx");
XSSFSheet s = wb2.getSheet("Test");
s.getRow(0).getCell(0).setCellType(CellType.STRING);
System.out.println(s.getRow(0).getCell(0).getStringCellValue());
wb2.close();
}
如您所见,这将创建一个 SXSSFWorkbook
,其中一行和一个单元格的值为“TEST”。
然后再次打开工作簿,并将该单元格的内容打印到控制台。
我希望在控制台上看到“TEST”,但我没有。输出为空。
- 如果我删除行
s.getRow(0).getCell(0).setCellType(CellType.STRING);
输出符合预期。
如果我从使用 SXSSFWorkbook
切换到 XSSFWorkbook
,则输出符合预期。
最好奇的是,如果我打开生成的 xlsx 文件,保存并再次关闭,然后 运行 上面代码的读取部分,输出符合预期。
有人对此有解释吗?
顺便提一句。我尝试了不同版本的 POI,每次都有相同的结果。
问题是 SXSSFWorkbook
默认使用内联字符串,因为这更适合流式传输方法。但是 XSSFWorkbook
期望当单元格类型为 CellType.STRING
.
时将字符串存储在共享字符串 table 中
因此,在创建 SXSSFWorkbook
后,sheet1.xml
中的单元格 XML 看起来像
<c r="A1" t="inlineStr">
<is>
<t>TEST</t>
</is>
</c>
类型 t
是 inlineStr
。并且单元格的值直接是字符串TEST。
但在 Cell.setCellType(CellType.STRING)
之后,类型 t
设置为 s
。这期望该值是一个数字,它是共享字符串 table 中字符串的索引。但是没有这样的。这就是 System.out.println(s.getRow(0).getCell(0).getStringCellValue());
无法打印任何内容的原因。
您可以 SXSSFWorkbook wb = new SXSSFWorkbook(null, 100, true, true)
强制 SXSSFWorkbook
也使用共享字符串 table。但这会降低流式方法的性能,因为所有字符串都需要存储在该共享字符串中 table 而不是直接将它们存储在单元格中。
共享字符串的好处 table 是节省内存,因为所有字符串只存储一次,当多个单元格使用相同的字符串时,只有它们的索引存储在单元格中。
Excel 本身从不使用内联字符串而不是共享字符串 table 来存储工作簿。因此,在 Excel 中打开并重新保存后,内联字符串被共享字符串 table 中的字符串索引替换,并且单元格类型始终为 s
而不是 inlineStr
。这就是为什么 Cell.setCellType(CellType.STRING)
将不再具有这种效果。
在使用 Apache POI 实现时,我 运行 陷入了 st运行ge 行为。我无法解释原因,所以如果有人可以提供一些提示,我很乐意听取他们的意见。对于我正在解决的问题,它甚至不是一个大障碍——在这一点上,它更像是一件好奇的事情。所以这里是:
public static void main(String[] args) throws EcatException, SQLException, IOException, Exception {
long ts = System.currentTimeMillis();
SXSSFWorkbook wb = new SXSSFWorkbook();
SXSSFSheet test = wb.createSheet("Test");
SXSSFRow r = test.createRow(0);
Cell c = r.createCell(0);
c.setCellValue("TEST");
wb.write(new FileOutputStream("D:/wb-" + ts + ".xlsx"));
wb.close();
XSSFWorkbook wb2 = new XSSFWorkbook("D:/wb-" + ts + ".xlsx");
XSSFSheet s = wb2.getSheet("Test");
s.getRow(0).getCell(0).setCellType(CellType.STRING);
System.out.println(s.getRow(0).getCell(0).getStringCellValue());
wb2.close();
}
如您所见,这将创建一个 SXSSFWorkbook
,其中一行和一个单元格的值为“TEST”。
然后再次打开工作簿,并将该单元格的内容打印到控制台。
我希望在控制台上看到“TEST”,但我没有。输出为空。
- 如果我删除行
s.getRow(0).getCell(0).setCellType(CellType.STRING);
输出符合预期。
如果我从使用
SXSSFWorkbook
切换到XSSFWorkbook
,则输出符合预期。最好奇的是,如果我打开生成的 xlsx 文件,保存并再次关闭,然后 运行 上面代码的读取部分,输出符合预期。
有人对此有解释吗? 顺便提一句。我尝试了不同版本的 POI,每次都有相同的结果。
问题是 SXSSFWorkbook
默认使用内联字符串,因为这更适合流式传输方法。但是 XSSFWorkbook
期望当单元格类型为 CellType.STRING
.
因此,在创建 SXSSFWorkbook
后,sheet1.xml
中的单元格 XML 看起来像
<c r="A1" t="inlineStr">
<is>
<t>TEST</t>
</is>
</c>
类型 t
是 inlineStr
。并且单元格的值直接是字符串TEST。
但在 Cell.setCellType(CellType.STRING)
之后,类型 t
设置为 s
。这期望该值是一个数字,它是共享字符串 table 中字符串的索引。但是没有这样的。这就是 System.out.println(s.getRow(0).getCell(0).getStringCellValue());
无法打印任何内容的原因。
您可以 SXSSFWorkbook wb = new SXSSFWorkbook(null, 100, true, true)
强制 SXSSFWorkbook
也使用共享字符串 table。但这会降低流式方法的性能,因为所有字符串都需要存储在该共享字符串中 table 而不是直接将它们存储在单元格中。
共享字符串的好处 table 是节省内存,因为所有字符串只存储一次,当多个单元格使用相同的字符串时,只有它们的索引存储在单元格中。
Excel 本身从不使用内联字符串而不是共享字符串 table 来存储工作簿。因此,在 Excel 中打开并重新保存后,内联字符串被共享字符串 table 中的字符串索引替换,并且单元格类型始终为 s
而不是 inlineStr
。这就是为什么 Cell.setCellType(CellType.STRING)
将不再具有这种效果。