在Java中使用Apache POI将16位字符写入.xlsx文件 [英] Write 16 bits character to .xlsx file using Apache POI in Java

查看:44
本文介绍了在Java中使用Apache POI将16位字符写入.xlsx文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Apache POI中遇到问题。 问题是,我尝试将16位字符值(如CJK统一表意文字扩展名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();

谢谢!

推荐答案

存在问题。但不包含从0x00000xFFFF的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的字符)被表示为一对字符值,第一个来自高代理范围(uD800-uDBFF),第二个来自低代理范围(uDC00-uDFFF)。

问题出在org.apache.xmlbeans.impl.store.Saver。这与private char[] _buf一起工作。但由于char最大值为0xFFFF0x100000x10FFFF之间的Unicode码点不可能存储在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是否介于0x100000x10FFFF之间。如前所述,这完全是不可能的。

它还将高代理范围(uD800-uDBFF)和低代理范围(uDC00-uDFFF)排除为坏字符。因此,将排除以一对字符值表示的代码点。

所以问题是由org.apache.xmlbeans.impl.store.Saver中的错误引起的。


修补程序:

目标:不排除高代理范围(uD800-uDBFF)和低代理范围(uDC00-uDFFF)作为坏字符。因此,存储为两个16位chars的U+10000以上的UNICODE代码点不会被排除在XML中。

下载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)
            );
    }

static final class OptimizedForSpeedSaverstatic final class TextSaver中。

编译Saver.java

xmlbeans-2.6.0.jar的备份存储在类路径之外的某个位置。

xmlbeans-2.6.0.jar->/org/apache/xmlbeans/impl/store/中的Saver$OptimizedForSpeedSaver.classSaver$TextSaver.class替换为新附带的

现在,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 chHighSurrogate还是LowSurrogate,如果是这样,它就不是坏字符。好的。

但它会检查char ch是否大于或等于0x10000。再次声明:这对于char是不可能的!achar的最大值为0xFFFF

这篇关于在Java中使用Apache POI将16位字符写入.xlsx文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆