Chris's Blog

Keep Walking......

Supplementary Characters in Java

工作中经常会涉及到文件处理,而fixlength类型的文件又是一种很常见的格式。众所周知,fixlength类型的数据就是每个字段对应一行数据中固定长度的字符,每个字段都有对应的start offset和end offset,用实现来表示就是String.substring(start, end),所以start和end的位置是至关重要的,一个字段对应错了,后面的字段就全错了。

在Java中使用UTF-16来表示unicode字符,一个字符就是16 bit,像String.length()就是返回有多少个16 bit。unicode支持的字符的code point范围是U+0000到U+10FFFF,这其中包括基本字符(BMP)和补充字符(supplementary character),基本字符时从U+0000到U+FFFF,补充字符从U+10000到U+10FFFF。在UTF-16编码中,基本字符占用一个16 bit,而补充字符占用两个16 bit。这样Java String的很多方法就会出现问题了,当然也包括上面提到的substring和length。那么如果fixlength文件中含有补充字符,则会导致字段map错误。

那现在来看如何解决这个问题,一个解决办法是对字符串做Base64编码,编码之后的字符都是单个16 bit了。但是这有两个弊端,一是Base64之后会使数据变大,有时我们会将这些fixlength的数据作为JMS Message,对于这种情况,数据变大是不建议的;另一个问题是Base64操作的CPU消耗会比较大,会影响到performance。因此虽然这种方法可以解决问题,但是不推荐。

另一个解决办法是使用IBM的ICU4J,这个API提供了很多国际化相关的工具类,使用它来重新实现我们用到的String方法,这里可以参考我写的一个工具类Unicode

因为我们一直用Spring Batch来处理文件,便查阅了一下源码看有没有考虑到supplementary character的问题,结果这个问题也被忽视了,看来supplementary character的使用还是比较少,但如果系统需要支持多语言的环境,还是自己处理一下比较好,之后我会重写一个Spring Batch的FixLengthItemWriter,增加对supplementary character的支持。

这里有一些资源可供参考:

Comments