浏览 1311 次
锁定老帖子 主题:Kuix乱码问题
该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2009-11-26
问题的来源还是前面Kuix国际化的乱码问题,之前没有深究,今天刚好看到了,发现了其中的缘由,先看一篇网上的帖子,讲的就是怎么读取UTF-8: 一、读取Unicode文件 /** * 读取Unicode编码文本文件 * @param resource String - 文件名 * @return String - Unicode文本 */ public static String read_Uni(String resource) { byte word_uni[] = new byte[1024]; String strReturn = null; InputStream is; try { is = instance.getClass().getResourceAsStream(resource); is.skip(2); // 跳过两个字节的文件头 is.read(word_uni); is.close(); StringBuffer stringbuffer = new StringBuffer(""); for (int j = 0; j < word_uni.length; ) { int l = word_uni[j++]; int h = word_uni[j++]; char c = (char) ((l & 0xff) | ((h << 8) & 0xff00)); stringbuffer.append(c); } strReturn = stringbuffer.toString(); } catch (IOException ex) { System.out.println(ex); } finally { is = null; } return strReturn; } 二、读取UTF-8文件 /** * 读取UTF-8编码文本文件 * @param resource String - 文件名 * @return String - UTF-8文本 */ public static String read_UTF(String resource) { byte word_utf[] = new byte[1024]; String strReturn = null; InputStream is; try { is = instance.getClass().getResourceAsStream(resource); is.read(word_utf); is.close(); strReturn = new String(word_utf, "UTF-8"); } catch (IOException ex) { System.out.println(ex); } return strReturn; }
再看看property文件的内容 YES=\u662F 这是GBK编码保存的,这里有点混乱,实机上myeclipse的property编辑器有个bug,编辑器里面保存的属性值全部用系统编码保存,也就是GBK码,如果你自己在源文件中写中文,而且文件属性是UTF-8,保存后是这样的: YES=\u00CA\u00C7 变成了4个字节,这种情况下Kuix读到的会是乱码,看Kuix.loadMessages private static synchronized void loadMessages(InputStream inStream) throws Exception { InputStreamReader inputStream = new InputStreamReader(inStream, "UTF-8"); ...... key = convertString(key); value = convertString(value); messageTable.put(key, value); 可以看到试图用UTF-8编码读取文件,而实际上property是用十六进制保存的,所以还需要用convertString做一次转换 private static String convertString(String theString) { char aChar; int len = theString.length(); StringBuffer outBuffer = new StringBuffer(len); for (int x = 0; x < len;) { aChar = theString.charAt(x++); if (aChar == '\\') { aChar = theString.charAt(x++); if (aChar == 'u') { // Read the xxxx int value = 0; for (int i = 0; i < 4; i++) { aChar = theString.charAt(x++); switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: // return KuixConstants.DEFAULT_UNKNOWN_I18N_MESSAGE STRING if there is any problem return "???"; } } outBuffer.append((char) value); } else { if (aChar == 't') { aChar = '\t'; } else if (aChar == 'r') { aChar = '\r'; } else if (aChar == 'n') { aChar = '\n'; } else if (aChar == 'f') { aChar = '\f'; } outBuffer.append(aChar); } } else { outBuffer.append(aChar); } } return outBuffer.toString(); } 关键在这一句outBuffer.append((char) value);它用两个字节做一个汉字了,所以出现乱码,实际上应该参考前面的方法: int l = word_uni[j++]; int h = word_uni[j++]; char c = (char) ((l & 0xff) | ((h << 8) & 0xff00)); 最后摘一段文章说明UTF-8编码的大小.(http://www.iteye.com/topic/113572) 1、UTF-8用几个字节表示一个汉字? 这各答案你可能了解,但也可能不了解,我敢打保票一半人会不清楚(包括特意查资料之前的我)。 了解这个对编程有什么影响? 以下我把对yoolywu的回答,转为帖子发表,以表重视。 yollywu的问: 引用 系统有两个子系统,一个是BS的,一个是delphi做的CS,中间的数据传输是通过XML进行传输的。在XML传输的功能实现后,要求对XML进行加密解密.加密解密算法是CS端用delphi写的,然后这边用JAVA写个同样的算法。现在碰到的一个问题是: 用该算法的时候,CS和BS各自都能够加解密,我这边的过程是这样的。。。。[但最后]中文始终是乱码 Java代码 StringBuffer strbuf = new StringBuffer(); try { FileInputStream in = new FileInputStream(file); int size = 0; byte [] buf = new byte[1024]; while ((size=in.read(buf)) != -1) { strbuf.append(new String(buf,0,size)); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } return strbuf; Qieqie的答: 以下的代码是错误的: Java代码 StringBuffer strbuf = new StringBuffer(); ... strbuf.append(new String(buf,0,size)); 第一、 你应该使用ByteArrayOutputStream,将InputStream的字节全部读出来,然后转成byte[]数组,最后在根据你和对方协议规定的字符集合(假设你们规定的是UTF-8,如果没有规定,那么就补充上吧),将byte[]变成String: String theString = new String(bytes, "UTF-8")。 不加"UTF-8"的new String,将使用Java环境设置的字符集,没有特别设置的情况下也就是操作系统的字符集。这是不可靠的。 第二、 不能使用byte[]+StringBuffer:StringBuffer是针对char操作的(String也是)。读取byte时可能刚好把一个多字节的char分成前后两批加入StringBuffer。这样就破坏了char的完整性了。而如果你使用UTF-8编码的中文,你就会中招,导致乱码(其实是因为你的读取是由于byte失去原有顺序导致的,跟一般的乱码还不一样) -- 在UTF-8编码集中,每个汉字使用 3个字符表示! 实践证明: 1、创建一个UTF-8编码的文件:weare.txt 2、写入三个字:“我们是” 3、运行以下代码: Java代码 public class UTF8 { public static void main(String[] args) throws IOException { String p = "weare.txt"; InputStream in = new FileInputStream(p); int read = in.read(new byte[1204]); System.out.println(read); } } 4、你会发现打印出来的是 9 ! 所以,byte[]+StringBuffer的使用方式是错误的! 不过可以使用StringBuffer + bufferedReader.readLine(),读出一行行后再加入StringBuffer。 或者第2楼说的stringbuffer+reader.read(char[])的形式(毕竟错误是由于byte[]导致的,而非StringBuffer) 参考资料: zh.wikipedia.org 写道 UTF-8 使用一至四个字节为每个字符编码。128 个 ASCII 字符(Unicode 范围由 U+0000 至 U+007F)只需一个字节,带有变音符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及马尔代夫语(Unicode 范围由 U+0080 至 U+07FF)需要二个字节,其他基本多文种平面(BMP)中的字符(CJK属于此类-Qieqie注)使用三个字节,其他 Unicode 辅助平面的字符使用四字节编码。
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |