Open GoogleCodeExporter opened 8 years ago
非常高兴能看到你这样的,对于源代码读得如此仔细的朋友��
�我当时写这个Util方法是为了读MP3
文件的标签,因为在读取MP3标签的时候,有可能是以ISO的格��
�读出来的,所以可能这个时候,
这个字符串就是不可读的,这个时候我会尝试再转换一下。
这个方法只在
com.hadeslee.yoyoplayer.tag.MpegInfo里面的
private String getChineseString(String source){
String temp=Util.convertString(source);
if(temp.indexOf("??")==-1&&temp.indexOf("�")==-1){
return temp;
}else{
return source;
}
}
这个方法用的,主要是判断是不是把乱码给读出来的,如果��
�的话,就尝试再转码一次,可能这
样考虑的并不周到,但是也是没有办法的办法。
当然,一个字符串,如果以特定的构造在内存里面造出来了��
�并且是可读的话,那就根本不需要
转码的,需要转码的前提是这个String对象可能是以错误的byte[
]的组织形式组织起来的,这个
时候,就需要再对它进行一次转码了。
再次感谢你的意见。
Original comment by hadeslee...@gmail.com
on 5 Aug 2009 at 2:06
如果你的那个字符串 source
本身已经解错了,那是无法通过对source的再操作把它捣鼓好��
�。
我们来看个实验:
String test = "安西四镇";
try {
byte[] data = test.getBytes("GBK");
String p = new String(data,"UTF-8");
System.err.println(p);
byte[] data2 = p.getBytes("GBK");
String p2 = new String(data2,"GBK");
System.err.println(p2);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
先构建了一个字符串"安西四镇",然后按照GBK编码输出一堆byt
e,接下来我故意以不匹配的编码
方案UTF-8去解这堆byte,得到一个p,然后打印p看看是什么,很
明显是乱码。此处的p就相当于
你的一个已经解错的source,接下我们尝试“转”它,我们将p�
��GBK输出一堆byte,然后再以GBK解
之,得到p2,打印P2看看是什么,很遗憾还是乱码。所以如果p
已经错了,后面你再对p做什么也
已经没用了,所以首先要保证p是以正确的编码方案解析了最�
��始的那堆byte,如果最开始的那堆
byte在某个外部文件,而其编码方案又不清楚,那确实比较麻�
��,即使要尝试多次解析,也是针
对最开始的那堆byte,而不是一个已经以某种不匹配编码方案�
��错的String。因为String解析某
堆byte后,它不是保存那堆byte的,而是翻成Unicode编码后再存��
�的。
假设一个字“天”在某一种编码方案中编成的二进制形式是��
�00110011”(只是假设),然后在
String的Unicode编码方案来看“天”假设应该是“11001100”,现��
�构造String并传正确的编码方案
解析这个“天",这时String解析当然能正确识别这个“00110011”�
��”天“,但是String不会内部存这
个“00110011”,而是去存”天“对应的Unicode编码,我这里假��
�是“11001100”。现在假设构造
String时传的编码方案不匹配,这时String解析对“00110011”也就
不理解成”天“了,至于到底理
解成什么就取决于所使用的编码方案,很可能是乱七八糟的��
�符假设是”瀹“,然后String会去保
存”瀹“对应的Unicode编码。这时候你再对这个String做什么操�
��也没用,因为这个String也就保
存了”瀹“对应的Unicode编码而已。
Original comment by carl...@gmail.com
on 6 Aug 2009 at 6:09
我可以写一个例子给你看一下。附件里面就是一段中文,用GB
K编码保存的“中华人民共和国”这七
个字,一共是14个字节。
运行测试的代码如下:
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
/**
*
* @author binfeng.li
*/
public class Test4 {
public static void main(String[] args) throws Exception {
//以二制的方法把文件的字节数组读进来
byte[] data = readBytes();
//然后再以ISO的编码格式构造一个字符串,这个字符串肯定是乱码了
String error = new String(data, "ISO-8859-1");
System.out.println("errorString:" + error);
//然后再尝试把这个字符串携带的byte[]读出来
byte[] b1 = error.getBytes("ISO-8859-1");
//再尝试用GBK的编码看一看
String gbkString = new String(b1, "GBK");
System.out.println("gbkString:" + gbkString);
}
private static byte[] readBytes() throws Exception {
FileInputStream fin = new FileInputStream("D:/Test.txt");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
int length = -1;
while ((length = fin.read(buffer)) != -1) {
bout.write(buffer, 0, length);
}
return bout.toByteArray();
}
}
***注意****:
Test.txt这个文件放在D盘的根目录下,然后再运行代码。
我们一开始是纯二进制的方法把它读入内存,保存成一个byte[
],这个时候,用ISO8859-1的编码
去把这一堆byte[]构造成一个String对象,这个时候,这个String��
�象肯定是不可读的。然后为
了让它可读,我尝试用这个String对象再次得到它的byte[],然��
�再用这个byte[]数组用GBK的编
码去构造一个String对象。这个时候,这个String对象就是可读��
�的。
com.hadeslee.yoyoplayer.tag.MpegInfo.getChineseString的方法它所能按受的
参数只是一个
String而已,这个String对象是第三方库提供的,因为我只实现��
�ID3v1和APEv2的标签实
现,ID3v2的标签是第三方实现的,它可能是以iso8859-1的编码去
读取MP3标签里面的那个字节
的,所以当里面有中文的时候,ISO的编码读出来的String肯定��
�乱码了,我这个时候再用上述的
方法折腾一下,就“可能”把原来读错的内容读正确成中文��
�。
这个方法是我后来加的,你可以运行YOYOPlayer看一下,把这个�
��法注释掉,或者直接在里面返
回原来的字符串本身,然后找一首MP3文件,用ID3V2的编码指定
标签,然后再在设置里面把ID3V2
的标签读取顺序排在最前面试试看,会不会有乱码的情况。
我在附件里面附上一首我在千千静听下用ID3V2标签注释的一首
歌,你先把
com.hadeslee.yoyoplayer.tag.MpegInfo.getChineseString这个方法的实现改成
直接返回传进来
的那个参数,打开这个MP3文件看看,会不会有乱码的情况发��
�。然后再用原来的实现再次打开这
首歌试试看。
再次感谢你的讨论:)
Original comment by hadeslee...@gmail.com
on 6 Aug 2009 at 9:32
Attachments:
或者把你上面的例子改成如下,也是可以的
String test = "安西四镇";
try {
byte[] data = test.getBytes("GBK");
String p = new String(data, "ISO-8859-1");
System.err.println(p);
byte[] data2 = p.getBytes("ISO-8859-1");
String p2 = new String(data2, "GBK");
System.err.println(p2);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
先是用ISO的编码构造错的一个字符串,然后再用ISO的编码把��
�始的byte[]尝试还原回来,这个
时候再用GBK就可以得到对的对象了。也就是说弄过去的编码��
�要弄回来的编码一样,比如尝试用
ISO去生成一个字符串,发现不对,再尝试用ISO得到byte[],这��
�byte[]就是原来的那个了,然
后可以再做别的变换,比如再用Big5尝试把byte[]生成字符串,�
��果不行,那就再用Big5把字符
串再转成原始的byte[],这个byte[]一直都是原始的,没有被改��
�的。
但是我用UTF-8尝试转过去,再转回来以后,就发现转不回来了
。
Original comment by hadeslee...@gmail.com
on 6 Aug 2009 at 9:40
关于java字符串的机制我说的还是对的,byte[]--以某种编码方��
�解析后-->char[](unicode的形式)---以某种
编码方案解析出-->byte[]
但是我关于:“如果你的那个字符串 source
本身已经解错了,那是无法通过对source的再操作把它捣鼓好��
�”这个
结论的确是错了。拿我上面假设的“天”字那个情况来说,��
�管编码方案不匹配时,解析“00110011”不理解成”天
“了,而是假设理解成”瀹“,然后存了”瀹“对应的Unicode�
��码。然后当你以这个编码方案getBytes时又将”瀹
“对应的Unicode编码转换成”瀹“的这个编码方案的编码,即0
0110011,然后再以一个匹配的编码方案来解这个
00110011,自然又能正确理解成“天”,当然字符串内部还是存
了“天”对应的Unicode编码.所以始终是符合这个机
制:byte[]--以某种编码方案解析后-->char[](字符串内部,unicode的��
�式)---以某种编码方案解析出-->byte
[]
Original comment by carl...@gmail.com
on 6 Aug 2009 at 4:00
既然读出来的就是byte[] 了,为什么要用String转来转去呢?
直接用读出来的byte[]
尝试用不同的方式解码不就可以了吗。这样也就不会存在UTF-8
转不回去
带来的问题了。
Original comment by tianzho...@gmail.com
on 19 Aug 2009 at 4:58
差不多还是可以的,对于字符串得到byte[]后用不同的编码解��
�,如果没有??或�的话大概就是正确的,否则
还用原来的字符串,这样就没有乱码了。
Original comment by hwxi...@gmail.com
on 7 Jan 2010 at 9:45
这个问题是有的,在j2ee开发当中就有这个问题存在,本身一�
��字符串的编码是GB2312,但是使用了错误的编码,结果字符串
当中的字符就是乱码,然后就可以使用错误的编码解码成byte[
],然后使用正确的编码就可以正确读出来。
Original comment by scn...@gmail.com
on 27 Sep 2012 at 1:20
Original issue reported on code.google.com by
carl...@gmail.com
on 4 Aug 2009 at 4:32