Java Apache POI 错误
在使用 Apache POI 实现时,我遇到了一个奇怪的行为。我无法解释原因,所以如果有人可以给出一些提示,我很乐意听到他们。对于我正在解决的问题来说,它甚至不是一个大障碍——在这一点上,它更多的是一个好奇心。事情如下:
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,每次都有相同的结果。
While working with the Apache POI Implementation I ran into a strange behaviour. I cannot explain the cause, so if anybody can give some hints, I would love to hear them. It is not even a big blocker for the problem that I was solving - at this point it is more a curiosity thing. So here it goes:
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();
}
As you can see, this will create a SXSSFWorkbook
with one row and one cell with the value "TEST".
Then opening the workbook againg, and print the content of that one cell to the console.
My expectation is to see "TEST" on the console, but I do not. The output is empty.
- If I remove the line
s.getRow(0).getCell(0).setCellType(CellType.STRING);
the output is as expected.
If I switch from using a
SXSSFWorkbook
toXSSFWorkbook
the output is as expected.And most curious, if I open the resulting xlsx file, save it and close it again, then running the read part of the above code, the output is as expected.
Is that something that someone has an explanation for?
Btw. I tried with different version of POI, it had the same results everytime.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于 SXSSFWorkbook 默认使用内联字符串,因为这对于流式处理方法更好。但是,当单元格类型为
CellType.STRING
时,XSSFWorkbook
希望将字符串存储在共享字符串表中。因此,在创建
SXSSFWorkbook
后,sheet1.xml
中的单元格 XML 看起来像“类型
t
为inlineStr
”。并且单元格值直接是字符串TEST。但在
Cell.setCellType(CellType.STRING)
之后,类型t
被设置为s
。这期望该值是一个数字,它是共享字符串表中字符串的索引。但没有这样的。这就是为什么System.out.println(s.getRow(0).getCell(0).getStringCellValue());
无法打印任何内容。您可以执行 SXSSFWorkbook wb = new SXSSFWorkbook(null, 100, true, true) 来强制 SXSSFWorkbook 也使用共享字符串表。但这会降低流式传输方法的性能,因为所有字符串都需要存储在共享字符串表中,而不是直接存储在单元格中。
共享字符串表的好处是节省内存,因为所有字符串仅存储一次,并且当多个单元格使用同一字符串时,只有它们的索引存储在单元格中。
Excel 本身从不使用内联字符串存储工作簿,而是使用共享字符串表。因此,在 Excel 中打开并重新保存后,内联字符串将替换为共享字符串表中字符串的索引,并且单元格类型始终为
s
而不是inlineStr
。这就是为什么Cell.setCellType(CellType.STRING)
将不再具有这种效果。The problem is that
SXSSFWorkbook
uses inline strings per default because this is better for the streaming approach. ButXSSFWorkbook
expects strings to be stored in a shared strings table when cell type isCellType.STRING
.So after creating the
SXSSFWorkbook
your cell XML insheet1.xml
looks likeThe type
t
isinlineStr
. And the cell value is the string TEST directly.But after
Cell.setCellType(CellType.STRING)
the typet
is sets
. And this expects the value to be a number which is the index of the string in the shared strings table. But there is not a such. That's whySystem.out.println(s.getRow(0).getCell(0).getStringCellValue());
cannot print anything.You could do
SXSSFWorkbook wb = new SXSSFWorkbook(null, 100, true, true)
to force theSXSSFWorkbook
to use shared strings table too. But that will cost performance in streaming approach because then all strings needs to be stored in that shared strings table instead of storing them directly in the cells.The benefit of the shared strings table is save memory because all strings only are stored once there and only their indexes are stored in the cells when multiple cells use the same string.
Excel itself never stores workbooks using inline strings instead of using shared strings table. So after opening and resaving in Excel the inline strings are replaced by indexes to strings in the shared strings table and cell types always are
s
instead ofinlineStr
. That's whyCell.setCellType(CellType.STRING)
will not have that effect anymore.