记一个奇怪的编码转换问题,及探讨“错误: 编码GBK的不可映射字符” 的原因

什么情况?

下面的一段简单代码,发现了奇怪的编码问题:

String docPath = "姝f枃";
// docPath = "正文"; // 注释1
System.out.println("default = " + docPath);

String docPath1 = new String(docPath.getBytes(), "GBK");
System.out.println("GBK = " + docPath1);
String docPath2 = new String(docPath.getBytes(), "UTF-8");
System.out.println("UTF-8 = " + docPath2);
String docPath3 = new String(docPath.getBytes(), "ISO-8859-1");
System.out.println("ISO-8859-1 = " + docPath3);

打印出来结果是?

default = 正文
GBK = 正文
UTF-8 = ????
ISO-8859-1 = ????

而把 注释1 打开,结果是:

default = ????
GBK = ????
UTF-8 = ????
ISO-8859-1 = ????

匪夷所思啊!  简直不可思议!!

查看文件编码:

 看起来编码是 ISO-8859-1 ?? (  经过后面的反复测试,发现, 这个高亮的选中行并不是 文件的实际编码!! ), 转换成utf-8, 结果显示:

 看起来当前文件编码是 GBK ? ———— 没错, 这个应该就是 文件的实际编码!!!

可是为什么 我明明 源码写的是 正文, 打印出来的是 “ 姝f枃 ” ?? 

难道是 console的显示编码的原因? console的显示编码  不可知,是不是 project encoding呢?

把Globa encoding 设置为GBK吧,结果还是一样的.. .

点击Reload Anyway , 结果,文件完全乱码了:

 这里说明一下 Reload 和 Convert 的区别, 测试发现, Reload  就相当于 重新用新的编码打散然后用项目编码格式编码,然后加载,然后覆盖;Convert 是直接用新编码转换然后覆盖;;

难道是IDEA的问题?

通过cmd 命令行执行,可以看到结果都是一样的:

  文件编码设置为GBK的时候, 出现了不可思议,如果文件编码设置是UTF-8, 则一切正常。。(同时可以看到 跟  -Dfile.encoding 参数是无关的!! 可以理解为  -Dfile.encoding 只在java 读取某些 外部 文件的时候的 默认编码?)

这就奇怪了。这说明class文件本身的内容就是那个了吧。跟IDEA 无关; 等等, 难道IDEA console 和 cmd 窗口的编码也是GBK?所以..

难道是。。。

新建一个文件TestEncoding.java,notepad++ 编辑, 把原来的内容拷贝过来,

import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.URLDecoder;
import java.util.Enumeration;

/**
 *
 * @author lk
 */
public class TestEncoding {

    public static void main(String[] args) throws  Exception {
//        System.out.println("args = " + args);
//        String localIp = getLocalIp();
//        System.out.println("localIp = " + localIp);

        String docPath = "姝f枃";
         docPath = "正文"; // 注释1
        testEncoding(docPath);
        System.out.println("正文 = " + docPath);
        System.out.println("姝f枃 = " + docPath);

    }

    private static void testEncoding(String docPath) throws UnsupportedEncodingException {
        System.out.println("默认 = " + docPath);

        // 测试默认-转换编码
        String docPath0 = new String(docPath.getBytes());
        System.out.println("默认 = " + docPath0);
        String docPath1 = new String(docPath.getBytes(), "GBK");
        System.out.println("默认 -> GBK = " + docPath1);
        String docPath2 = new String(docPath.getBytes(), "UTF-8");
        System.out.println("默认 -> UTF-8 = " + docPath2);
        String docPath3 = new String(docPath.getBytes(), "ISO-8859-1");
        System.out.println("默认 -> ISO-8859-1 = " + docPath3);

        // 测试转换编码
        String docPath00 = new String(docPath.getBytes("UTF-8"), "GBK");
        System.out.println(" -> UTF-8 -> GBK = " + docPath00);
        String docPath01 = new String(docPath.getBytes("UTF-8"),"UTF-8");
        System.out.println(" -> UTF-8 -> UTF-8 = " + docPath01);

        docPath00 = new String(docPath.getBytes("GBK"), "GBK");
        System.out.println(" -> GBK -> GBK = " + docPath00);
        docPath01 = new String(docPath.getBytes("GBK"),"UTF-8");
        System.out.println(" -> GBK -> UTF-8 = " + docPath01);
    }

}

编码设置为UTF-8 ,

javac编译,然后java执行一下,发现错误:

仔细检查发现,,正是 “姝f枃” 这几个字符,在utf-8 格式下是不能被解析的!! 替换为空格 “”就好了,但是 编译执行后发现 还是不对:

真是不可思议!  可见, 这个跟 是否是 IDEA 无关,这个是 编译之后的 class 文件本身内容的关系;

 有时候出现:

 哦, 错误: 编码GBK的不可映射字符。 ———— 连编译都不通过了!!

转换为GB2312,出现

点击“是”

 可见出现了乱码,特别注意到, 上面的页面的字样和 之前执行class 打印出来的 是一样的!

javac 同样有错:

郁闷了, 先把文件开始的那个文件内容复制,然后把Notepad++ 里的文件内容清空,然后编码转换为GB2312,然后复制文件内容; 

然后javac, java 一切正常了。

然后编码格式强制转换为Utf-8, 出现下面的情况:

然后javac编译, java运行,发现结果跟 在IDEA中发现的一样的奇怪、不可思议; 可见,刚刚的转换过程,出现了问题, 应该来说,不能直接这么转换!!

然后呢,再转换为GB2312,

一切又正常了!!

为什么?

为此,我能想到的唯一的 解释是:编译之后的 class 文件本身内容不同,把不同看起来相同的 源码,用不同的编码格式保存,然后编译,然后对比class, 果然发现不同:

怎么办?

总之,

1 可见不是可得!! 有些java源码文件,其中的字符看起来 是正确编码,其实那个是 用其他编码格式编码的结果! 但是为什么 它在源码中显示正确呢? 那大概是因为 两种编码格式比如 UTF-8和GBK 有一定的交集, 编码reload或convert之后 ,呈现了相同的展现,但其实 内容是不同的!—— 这TM 确实有些不好理解啊!换言之, 源码的字样 到了 class 中会发生一些变化! 两者不是相同的!! 所以打印出来的  会不同!

2 编码转换的时候要小心,特别是 reload,很容易出问题的! 不能直接这么转换。如果用Notepad++ 转换文件编码格式, 出现了 “无法恢复警告” 那么就不能转;同样, 用IDEA reload 也要小心。

3 还是 class 内容的不同;

猜你喜欢

转载自www.cnblogs.com/FlyAway2013/p/12115243.html