编码(二):Java中编码问题

Java中编码分析

Java 内存以 UTF-16 对字符进行存储,所以在 Java 中1个char占两个字节。通过下面的例子分析 Java 编码细节:

public static void main(String[] args) throws UnsupportedEncodingException {
        String s = "My name is 程序员";
        toHex(s.toCharArray());  

        // 字符串 s 按照 ISO-8859-1 编码
        byte[] iso8859 = s.getBytes("ISO-8859-1");
        toHex(iso8859); 

        // 字符串 s 按照 gb2312 编码
        byte[] gb2312 = s.getBytes("GB2312");
        toHex(gb2312); 

        // 字符串 s 按照 GBK 编码
        byte[] gbk = s.getBytes("GBK");
        toHex(gbk);

        // 字符串 s 按照  UTF-16  编码
        byte[] utf16 = s.getBytes("UTF-16");
        toHex(utf16);

        // 字符串 s 按照  UTF-8  编码
        byte[] utf8 = s.getBytes("UTF-8");
        toHex(utf8);        
    }

结果

  1. 字符串 “My name is 程序员”的 char 数组为:4d 79 20 6e 61 6d 65 20 69 73 20 7a0b 5e8f 5458,按照不同的编码方式转成相应的字节:

    • 按照 ISO-8859-1:

    按照iso-8859-1
    1)从上图可以看出,ISO-8859-1是单字节编码。
    2)“程序员”三个汉字经过iso-8859-1编码后变成“3f”,“3f”也就是“?”,因为iso-8859-1适用于西欧字符,并不认识汉字,这种现象我们称之为“黑洞”。常见中文变成“?”,可能就是错误的使用了ios-8859-1编码。

    • 按照GB2312:

      gb2312

    • 按照GBK:

    GBK
    使用gb2312和GBK编码时,需要查码表,从码表中找到每个字符对应的字节,然后拼装成字节数组。

    • 按照UTF-16

    这里写图片描述
    1)utf-16占两个字节,单字节范围的字符高位补0,汉字变成两个字节。
    2)使用utf-16编码char转成byte后,前面多出两个字节用来保存BYTE_ORDER_MARK值,用来指明是大端序还是小端序(不同的处理器对多字节的处理方式不同)。
    3)从上图可以看出使用utf-16编码只是将字符的高位和地位拆分成两个字节,所以效率很高。

    • 按照UTF-8

    utf-8
    1)utf-8对单字节范围的字符任然使用单字节编码,对汉字使用3字节编码。

Java编码实现过程

String.getBytes(charsetName)过程:
getBytes时序图
Java 编码时序图
从上图可以看出,通过charsetName找到Charset类,然后根据这个字符集生成CharsetEncoder对象,这个类是所有编码集的父类,这对不同的编码集,其子类中定义了具体的实现,有了CharsetEncoder对象,就可以调用encode方法进行编码。

Java中编码的应用场景

  • IO读取
public void writerString2File(String filePath, String charsetName) {
    try(FileOutputStream out = new FileOutputStream(filePath);
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, charsetName))) {

        writer.write("写字符到文件中");

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

    public void readStringFromFile(String filePath, String charsetName) {
    try(FileInputStream in = new FileInputStream(filePath);
            BufferedReader reader = new BufferedReader(new InputStreamReader(in, charsetName))) {
        StringBuffer sb = new StringBuffer();
        char[] cbuf = new char[1024];
        int len = 0;
        while((len = reader.read(cbuf)) != -1) {
            sb.append(cbuf, 0, len);
        }

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
  • 在内存中操作编码
public void test() throws UnsupportedEncodingException {
    String s = "Java是门很好的编程语言";
    byte[] buffer = s.getBytes("utf-8");
    String news = new String(buffer, "utf-8");
    System.out.println(news);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值