zoukankan      html  css  js  c++  java
  • IO流__【转换流的字符编码】【编码与解码】【字符编码-“联通”】



    常见的码表

    ASCII: 美国标准信息交换码。用一个字节7位可以表示。
    ISO8859-1 拉丁码表。欧洲码表用一个字节8位表示。
    GB2312 中国的中文编码表。
    GBK 中国的中文编码表升级,融合了更多的中文文字符号。
    Unicode 国际标准码,融合了多种文字。所有文字都用两个字节来表示,Java语言就是unicode
    UTF-8 最多用三个字节来表示一个字符。

    转换流的字符编码

    示例 :

    import java.io.*;
    class  EncodeStream
    {
    	public static void main(String[] args) throws IOException
    	{
    //		writeText();
    		readText();
    	}
    	public static void readText() throws IOException{
    		InputStreamReader isr = new InputStreamReader(new FileInputStream("gbk.txt"),"GBK");//转换流按照指定码表解码
    		char[] buf = new char[8];
    		int len = isr.read(buf);
    		String s = new String(buf,0,len);
    		System.out.println(s);
    		isr.close();
    	}
    	public static void writeText() throws IOException{
    		OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("UTF-8.txt"),"UTF-8");//转换流按指定码表编码
    		osw.write("你好");
    		osw.close();		
    	}
    }
    调用writeText();方法;将转换流编码分别指定为(("GBK.txt"),gbk)和(("UTF-8.txt",UTF-8)),生成GBK和UTF-8两个txt文档;

    发现同样是“你好”两个字符,UTF-8编码的占了6个字节,gbk编码的占了4个字节

    调用readText();方法;

    当其各自按照各自指定的码表解码时都能够读取出“你好”;当其按照非指定的码表解码时会产生乱码(左图);“你好”在GBKUTF-8两种编码中的字节数组(右图)


    分析原因图解:其各自的编解码方式不同导致了结果


    -------------------------------------------------------------------------------------------------------------------------------

    编码与解码:

    编码:字符串变成字节数组;String -->byte[]; (String类的方法):str.getBytes(charsetName);;将该字符串按照指定编码表编码。
    解码:字节数组变成字符串;byte[] -->String; (String类的构造方法):new String(byte[],charsetName);通过使用指定的 charset 解码指定的 byte 数组。

    方法空参则代表使用系统默认的编码表,中文为GBK,设定charsetName可以用指定的编码表

    编码与解码示例:

    import java.util.*;	//Arrays类
    class  EncodeDemo
    {
    	public static void main(String[] args) throws Exception
    	{
    		String s = "你好";
    		byte[] b1 = s.getBytes("GBK");//GBK编码
    		sop(Arrays.toString(b1));
    		String s1 = new String(b1,"ISO8859-1");	//解码,码表不对应,产生乱码
    		sop("s1:"+s1);
    		byte[] b2 = s1.getBytes("ISO8859-1");	//将其解码出的乱码再次编码,字节数组
    		sop(Arrays.toString(b2));
    		String s2 = new String(b2,"GBK");//解码
    		sop("s2:"+s2);
    	}
    	public static void sop(Object obj){
    		System.out.println(obj);
    	}
    }

    运行结果:

    图解:


    实际应用场景:客户端与服务器端的码表不一致,例如一个服务器端的网页在客户端打开时就可能会产生乱码,所以要加上一个编码与解码的过程,避免这种情况的发生

    开发中会经常遇到这种情况,要注意!

    注意事项:

    GBK不能用UTF-8作为中间码来编解码,如果将上文EncodeDemo中“ISO8859-1”改成“utf-8”

    运行结果:


    产生这种结果的原因是:UTF-8一个字符所占的字节个数比GBK(2个)要多,utf-8解码后的乱码经其再次编译后产生的字节数组与GBK编译后的字节数组不一致

    要避免这种情况。


    字符编码-“联通”

    在空记事本上输入“联通”两个字,保存后再次打开,会发现只有两个乱码

    首先要了解UTF-8修改版特点:

    两个字节110开头,三个字节1110开头


    通过打印其字节数组和二进制位:

    import java.util.*;
    class  EncodeDemo2
    {
    	public static void main(String[] args) throws Exception//加入编码表会抛异常
    	{
    		String s = "联通";
    		byte[] by = s.getBytes("gbk");	//gbk编码
    		sop(Arrays.toString(by));	//打印字节数组
    		for (byte b:by ){
    			sop(Integer.toBinaryString(b&255));//打印字节数组的二进制位
    		}
    	}
    	public static void sop(Object obj){
    		System.out.println(obj);
    	}
    }
    运行结果:


    分析:通过“联通”的字节数组的二进制位发现:其刚好UTF-8两个字符的标准,所以原本是GBK编码的文件在再次打开时成了UTF-8解码,所以造成了乱码

    在简体中文操作系统中默认的本地字符集编码是GBK编码,除非你在保存记事本文本文件时候选择了其他编码方式,否则用记事本录入的字符信息将使用GBK编码进行储存。巧合的是,“联通”这两个字符的GBK编码具有UTF-8编码的特征,记事本犯下的错误正是将GBK编码存放的记录有“联通”两个字符的文件误认为UTF-8编码的文件。



  • 相关阅读:
    不同数据类型在不同编译器下字节大小
    gbk/utf8/gb2312 编码中汉字字母数字所占字节数
    剑指Offer-12 矩阵中的路径
    螺旋矩阵(数组)问题(网易考点)
    C++ 多继承导致的指针偏移问题
    面试题--链表实现插入排序
    C++ 二叉树的深度优先遍历(前中后序)以及广度优先遍历
    (转)软连接和硬链接作用以及区别
    TCP/IP网络五层结构理解以及数据传输流程的理解图示
    常考知识点:进程与线程,多进程与多线程
  • 原文地址:https://www.cnblogs.com/Joure/p/4337208.html
Copyright © 2011-2022 走看看