锁定老帖子 主题:Unicode文件中文编码解码的实现
精华帖 (1) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2008-07-29
<!----> 近期开发一个处理WMA 文件的公用类库,发现最头疼的问题不是WMA编码格式的问题而是Unicode这种文件格式的问题.经过近两天的研究,终于解决了这一问题,并且在今天下午基本完成了WMA文件解析处理类库的开发.利用余下的一点时间偷偷将Unicode相关的内容整理一下,希望我的老板不要发现这件事情.o(∩_∩)o...哈哈 字节流的字符编码:
<!----> <!----> UTF 的字节序和 Byte Order Mark UTF-8 以字节为编码单元,没有字节序的问题。 UTF-16 以两个字节为编码单元,在解释一个 UTF-16 文本前,首先要弄清楚每个编码单元的字节序。例如收到一个 “ 奎 ” 的 Unicode 编码是 594E , “ 乙 ” 的 Unicode 编码是 4E59 。如果我们收到 UTF-16 字节流 “594E” ,那么这是 “ 奎 ” 还是 “ 乙 ” ? <!----> <!----> Unicode 规范中推荐的标记字节顺序的方法是 Byte Order Mark 。而是 Byte Order Mark 。在 UCS 编码中有一个叫做 "ZERO WIDTH NO-BREAK SPACE" 的字符,它的编码是 FEFF 。而 FFFE 在 UCS 中是不存在的字符,所以不应该出现在实际传输中。 UCS 规范建议我们在传输字节流前,先传输字符 "ZERO WIDTH NO-BREAK SPACE" 。 这样如果接收者收到 FEFF ,就表明这个字节流是 Big-Endian 的;如果收到 FFFE ,就表明这个字节流是 Little-Endian 的。 <!----> <!----> UTF-8 不需要 Byte Order Mark 来表明字节顺序,但可以用 Byte Order Mark 来表明编码方式。字符 "ZERO WIDTH NO-BREAK SPACE" 的 UTF-8 编码是 EF BB BF 。所以如果接收者收到以 EF BB BF 开头的字节流,就知道这是 UTF-8 编码了。 如同样是字符
"A"
﹐在以下几种格式中的存储形式分别是﹕
<!----> <!----> 因此在一段字节流开始时﹐如果接收到以下字节﹐则分别表明了该文本文件的编码。
<!----> <!----> ANSI
文件格式的字节流﹕
<!----> <!----> <!----> <!----> 解码 <!----> <!----> 处理 WMA 文件时 , 例如读到一首歌曲的 title 名称为 ”2046 沧海一声笑 ” 使用 byte[] 直接在文件中读到的 [50, 0, 48, 0, 52, 0, 54, 0, -89, 108, 119, 109, 0, 78, -16, 88, 17, 123] 50, 0 对应 2 48, 0 对应 0 52, 0 对应 4 54, 0 对应 6 -89, 108 对应 沧 119, 109 对应 海 0, 78 对应 一 -16, 88 对应 声 17, 123 对应 笑 <!----> <!----> readUnicodeByte2Hex 的代码实现Unicode字节到16进制码的转换
public static String readUnicodeByte2Hex(byte[] temp) throws IOException { <!----> <!----> 转化为 16 进制 3200 3000 3400 3600 a76c 776d 004e f058 117b 2 0 4 6 沧 海 一 声 笑 <!----> <!----> <!----> <!----> System.out.println((char) Integer.parseInt("a76c", 16)); 输出 : 乱码 ?. 于是 考虑到可能是 Byte Order Mark 的原因 , 尝试将沧字的 16 进制码的高低位进行交换 System.out.println((char) Integer.parseInt("6c a7", 16)); 输出 : 沧
decodeHexToChinese的代码实现
public static String decodeHexToChinese(String hex) { <!----> <!----> 编码 <!----> <!----> 例如尝试将 ”2046 沧海一声笑 ” 写入 WMA 文件 将字符串转换为 hex 的字符串 , 然后转化为 byte 数组 writeNew2Buff
public static void writeNew2Buff(String title,byte[] titleBuff ) throws NumberFormatException, //将16进制字符串转化为byte格式
toHexString 将字符串转化为符合Unicode格式规范的16进制字符串
public static String toHexString(String s){
编码为 [50, 0, 48, 0, 52, 0, 54, 0, -89, 108, 119, 109, 0, 78, -16, 88, 17, 123] <!----> <!----> 对于写入数字的特殊处理 由于数字存在精度的问题 , 因此 unicode 的文件中数字的精度有 2byte,4byte,8byte 的差别 因此写入数字的时候要考虑位数的差别问题 . 而且空白位要使用 0 进行补足 . 下面给出int转化为2byte和4byte的技术实现. <!----> public static byte[] intTo2Bytes(int s) { 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2008-07-30
今天早上发现temp = s.getBytes("Unicode");在winxp和win2k上面得到的结果是不同的.
winxp和win2k上面对字符串转Unicode的Byte Order Mark 是不同的,不过可以通过 byte数组的前两位进行判断,通过判断ffef还是efff来辨别是big-endian或是litte-endian.toHexString方法代码更新如下 public static String toHexString(String s){ StringBuffer sb=new StringBuffer(""); byte[] temp; try { temp = s.getBytes("Unicode"); if(-1==temp[0]&&-2==temp[1]){ for(int i=2;i<temp.length;i+=2){ if((temp[i]&0xff)<16){ sb.append("0"+Integer.toHexString(temp[i]&0xff)); }else{ sb.append(Integer.toHexString(temp[i]&0xff)); } if((temp[i+1]&0xff)<16){ sb.append("0"+Integer.toHexString(temp[i+1]&0xff)); }else{ sb.append(Integer.toHexString(temp[i+1]&0xff)); } } }else if(-2==temp[0]&&-1==temp[1]){ for(int i=2;i<temp.length;i+=2){ if((temp[i+1]&0xff)<16){ sb.append("0"+Integer.toHexString(temp[i+1]&0xff)); }else{ sb.append(Integer.toHexString(temp[i+1]&0xff)); } if((temp[i]&0xff)<16){ sb.append("0"+Integer.toHexString(temp[i]&0xff)); }else{ sb.append(Integer.toHexString(temp[i]&0xff)); } } } return sb.toString(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } return s; } |
|
返回顶楼 | |
发表时间:2009-06-13
能提供源码就更好,感激不尽!
|
|
返回顶楼 | |
浏览 4891 次
winxp和win2k上面对字符串转Unicode的Byte Order Mark 是不同的,不过可以通过
byte数组的前两位进行判断,通过判断ffef还是efff来辨别是big-endian或是litte-endian.toHexString方法代码更新如下
public static String toHexString(String s){
StringBuffer sb=new StringBuffer("");
byte[] temp;
try {
temp = s.getBytes("Unicode");
if(-1==temp[0]&&-2==temp[1]){
for(int i=2;i<temp.length;i+=2){
if((temp[i]&0xff)<16){
sb.append("0"+Integer.toHexString(temp[i]&0xff));
}else{
sb.append(Integer.toHexString(temp[i]&0xff));
}
if((temp[i+1]&0xff)<16){
sb.append("0"+Integer.toHexString(temp[i+1]&0xff));
}else{
sb.append(Integer.toHexString(temp[i+1]&0xff));
}
}
}else
if(-2==temp[0]&&-1==temp[1]){
for(int i=2;i<temp.length;i+=2){
if((temp[i+1]&0xff)<16){
sb.append("0"+Integer.toHexString(temp[i+1]&0xff));
}else{
sb.append(Integer.toHexString(temp[i+1]&0xff));
}
if((temp[i]&0xff)<16){
sb.append("0"+Integer.toHexString(temp[i]&0xff));
}else{
sb.append(Integer.toHexString(temp[i]&0xff));
}
}
}
return sb.toString();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return s;
}