簡體   English   中英

使用Java中的Apache POI將16位字符寫入.xlsx文件

[英]Write 16 bits character to .xlsx file using Apache POI in Java

我在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();

謝謝!

問題存在。 但不是從0x00000xFFFF 16位(2字節)Unicode字符。 它的字符在Unicode編碼中需要超過2個字節。 這些是在Java字符中作為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 max值為0xFFFF ,因此從0x100000x10FFFF 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是否在0x100000x10FFFF之間。 如上所述,這根本不可能。

此外,它排除了高代理范圍(\\ uD800- \\ uDBFF)和低代理范圍(\\ uDC00- \\ uDFFF)作為壞字符。 因此,將排除作為一對char值的代碼點表示。

因此問題是由org.apache.xmlbeans.impl.store.Saver的錯誤引起的。


補丁:

目標:不排除高代理范圍(\\ uD800- \\ uDBFF)和低代理范圍(\\ uDC00- \\ uDFFF),作為壞字符。 因此,在XML不會排除存儲為兩個16位chars 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)
            );
    }

static final class OptimizedForSpeedSaverstatic final class TextSaver

編譯Saver.java

在類路徑之外的某處存儲xmlbeans-2.6.0.jar的備份。

使用新的Saver$TextSaver.class替換Saver$TextSaver.class Saver$OptimizedForSpeedSaver.classSaver$TextSaver.classxmlbeans-2.6.0.jar - > /org/apache/xmlbeans/impl/store/

現在,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。 好。

但是它會檢查char ch是否大於或等於0x10000 再說一次:這對於char是不可能的! char的最大值是0xFFFF

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM