loading ...
loading...

2007-07-05 | JXL 的 Excel 导入 乱码 问题

分享
标签: JXL  Excel  导入  乱码  问题 
网上开源的操作excel的包有很多,比较常用的是jexcelapi和apache的POI,jexcelapi就是以前提到过的jxl,说一下前不久使用jxl时出现的问题。
 
使用的jxl版本为4.6
 
由于在工程中使用jxl来处理一个excel文件,在读取中文字符时都出现了乱码,看了一下jxl的javadoc,先是设置了一下workbooksettings的编码,结果一样。然后试图通过转码找到
字符的原始编码,gb2312,utf-8等差不多四五种互相转换结果都不对。
 
没办法,只好下了jxl的源代码单步执行,最后跟到了这个方法。(jdk1.4.2)
public static String getUnicodeString(byte[] d, int length, int pos)
  {
    try
    {
      byte[] b = new byte[length * 2];
      System.arraycopy(d, pos, b, 0, length * 2);
      return new String(b, "UnicodeLittle");
    }
    catch (UnsupportedEncodingException e)
    {
      // Fail silently
      return "";
    }
  }
return以后就出现了乱码。
 
这句怎么看也找不出毛病,后来换用了jdk1.5竟然没有问题,中文字符被正确返回。
 
后来我将unicodelittle换成utf-16LE,之所以这样换,是因为我没见过有人这么写,
但如果没报这个UnsupportedEncodingException的话,应该是支持这种写法的,所以换得有点没有原因。更奇怪的是换了以后,结果正确了,在jdk1.4下。
 
于是怀疑jdk1.4 到1.5可能对这个unicodelittle作了修改,于是写了个JUNIT用unicodelittle返回一个中文字符的编码,换成16进制后,发现是1.4和1.5都一样。
(成了悬疑,希望有人能解答)
 
那究竟unicodelittle和utf-16LE有什么区别呢?原来用unicodelittle编码后字节数组中会带上BOM标志,而utf-16LE不会。
 
最终的解决办法是在源代码中找到jxl.biff.StringHelper这个类把

public static byte[] getUnicodeBytes(String s)
  {
    try
    {
      byte[] b = s.getBytes("UnicodeLittle");

      // Sometimes this method writes out the unicode
      // identifier
      if (b.length == (s.length() * 2 + 2))
      {
        byte[] b2 = new byte[b.length - 2];
        System.arraycopy(b, 2, b2, 0, b2.length);
        b = b2;
      }
      return b;
    }
    catch (UnsupportedEncodingException e)
    {
      // Fail silently
      return null;
    }
  }

 
 public static String getUnicodeString(byte[] d, int length, int pos)
  {
    try
    {
      byte[] b = new byte[length * 2];
      System.arraycopy(d, pos, b, 0, length * 2);
      return new String(b, "UnicodeLittle");
    }
    catch (UnsupportedEncodingException e)
    {
      // Fail silently
      return "";
    }
  }
这个方法中的UnicodeLittle改成utf-16LE.
另外,把jxl.read.biff.BoundsheetRecord中的UnicodeLittle换成UTF-16LE

  public BoundsheetRecord(Record t) {
        super(t);
        byte[] data = getRecord().getData();
        offset = IntegerHelper.getInt(data[0], data[1], data[2], data[3]);
        typeFlag = data[5];
        visibilityFlag = data[4];
        length = data[6];

        if (data[7] == 0) {
            // Standard ASCII encoding
            byte[] bytes = new byte[length];
            System.arraycopy(data, 8, bytes, 0, length);
            name = new String(bytes);
        } else {
            // little endian Unicode encoding
            byte[] bytes = new byte[length * 2];
            System.arraycopy(data, 8, bytes, 0, length * 2);
            try {
                name = new String(bytes, "UTF-16LE");
            } catch (UnsupportedEncodingException e) {
                // fail silently
                name = "Error";
            }
        }
    }

 
然后重新打包使用,一切OK。
 
 
最后说点题外话,自己找到解决办法以后上网搜了一下unicodelittle和JexcelAPI
竟然发现已经有人遇到这样的问题,并且也用相同的办法解决。于是感慨自己实在点背,花了一整天时间在这上面,早知道用这个搜一下就好了。
 
分享 分享 |  评论 (1) |  阅读 (?)  |  固定链接 |  类别 (研习小屋) |  发表于 14:36  | 最后修改于 2007-07-11 12:12
搜狐博客温馨提示:警惕博客留言诈骗, 搜狐博客管理员的正确地址为http://admin.blog.sohu.com, 其他都是冒牌。搜狐博客官方不会要求参加活动的各位博友缴纳任何的手续费用。请勿轻信留言、评论中的中奖信息,更不要拨打陌生电话及向陌生帐户汇款,谨防受骗!识别更多网络骗术,请 点击查看详情
正在读取评论信息...
您还未登录,只能匿名发表评论。或者您可以 登录 后发表。
 
  一个单亲妈妈的心愿:治好7岁儿子的白血病
表  情:
加载中...
回复通知: 同时用小纸条通知对方该回复