我在Apache POI中遇到问题。 问题是,我尝试将16位字符值(例如CJK Unified Ideographs Extension B)放到.xlsx文件中。但是,单元格值在生成的.xlsx文件中成为问号(如????)。
任何人都知道如何使用.xlsx格式处理Apache POI中的16位字符值
我的POI版本是3.14
代码示例如下:
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Test");
XSSFRow row1 = sheet.createRow(0);
XSSFCell r1c1 = row1.createCell(0);
r1c1.setCellValue(""); // value of CJK Unified Ideographs Extension B
XSSFCell r1c2 = row1.createCell(1);
FileOutputStream fos =new FileOutputStream("D:/temp/test.xlsx");
workbook.write(fos);
fos.close();
谢谢!
答案 0 :(得分:2)
存在问题。但不是0x0000
到0xFFFF
的16位(2字节)Unicode字符。它的字符在Unicode编码中需要超过2个字节。这些是在Java Character中提及为Unicode code points
的字符:" Unicode代码点用于U + 0000和U + 10FFFF之间范围内的字符值,并使用Unicode代码单元对于16位字符值,它是UTF-16编码的代码单元。" Java平台在char数组和String和StringBuffer类中使用UTF-16表示。在此表示中,补充字符(代码点大于U + FFFF的字符)表示为一对char值,第一个来自高代理范围,(\ uD800- \ uDBFF),第二个来自低 - 代理范围(\ uDC00- \ uDFFF)。
问题在于org.apache.xmlbeans.impl.store.Saver
。这适用于private char[] _buf
。但由于char
最大值为0xFFFF
,因此0x10000
到0x10FFFF
的Unicode代码点无法存储在char
中。因此,它将被存储为一对char值。
有一种方法
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
private boolean isBadChar ( char ch )
{
return ! (
(ch >= 0x20 && ch <= 0xD7FF ) ||
(ch >= 0xE000 && ch <= 0xFFFD) ||
(ch >= 0x10000 && ch <= 0x10FFFF) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
该代码完全错误,因为它检查char
是否在0x10000
和0x10FFFF
之间。如上所述,这根本不可能。
此外,它排除了高代理范围(\ uD800- \ uDBFF)和低代理范围(\ uDC00- \ uDFFF)作为坏字符。因此,将排除作为一对char值的代码点表示。
因此问题是由org.apache.xmlbeans.impl.store.Saver
中的错误造成的。
修补程序:
目标:不排除高代理范围(\ uD800- \ uDBFF)和低代理范围(\ uDC00- \ uDFFF),作为坏字符。因此,在chars
中不会排除存储为两个16位XML
的U + 10000以上的Unicode代码点。
下载Saver.java。将private boolean isBadChar ( char ch )
更改为
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
private boolean isBadChar ( char ch )
{
return ! (
(ch >= 0x20 && ch <= 0xFFFD ) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
{p} static final class OptimizedForSpeedSaver
和static final class TextSaver
中的。
编译Saver.java
。
在类路径之外的某处存储xmlbeans-2.6.0.jar
的备份。
替换Saver$OptimizedForSpeedSaver.class
中的Saver$TextSaver.class
和xmlbeans-2.6.0.jar
- &gt; /org/apache/xmlbeans/impl/store/
与新的compiiled。{/ p>
现在,U + 10000以上的Unicode代码点将存储在sharedStrings.xml
。
<强>声明:强>
这没有经过充分测试。所以不要在生产中使用它。这里仅显示描述问题。也许xmlbeans.apache.org
上的某些程序员会找到时间来org.apache.xmlbeans.impl.store.Saver
正确解决问题。
<强>更新强> 现在有一个xmlbeans-2.6.2.jar可用。这已包含补丁。
<强>更新强> 现在有一个xmlbeans-3.0.0.jar可用。这也包含补丁。
它确实:
/**
* Test if a character is valid in xml character content. See
* http://www.w3.org/TR/REC-xml#NT-Char
*/
static boolean isBadChar ( char ch )
{
return ! (
Character.isHighSurrogate(ch) ||
Character.isLowSurrogate(ch) ||
(ch >= 0x20 && ch <= 0xD7FF ) ||
(ch >= 0xE000 && ch <= 0xFFFD) ||
(ch >= 0x10000 && ch <= 0x10FFFF) ||
(ch == 0x9) || (ch == 0xA) || (ch == 0xD)
);
}
因此,它会检查char ch
是HighSurrogate
还是LowSurrogate
,如果是,那么它不是一个错误的字符。行。
但是它检查char ch
是否大于或等于0x10000
。再说一次:char
这是不可能的! char
的最大值为0xFFFF
。