java 编码 解决中文乱码

目录

1 java编码

常用转码方式

1 在我们Java中定义了一个String,其编码方式是啥?

2 编码和编码格式的区别是什么?

3 按字节

4 按字符

5 字节&字符转换


1 java编码

ASCII:美国标准信息交换表

ISO8859-1:拉丁码表,欧洲码表

GB2312:中国的中文编码表

GBK:中国的中文编码表升级

GB18030:GBK的取代版本

BIG5:通用于香港、台湾地区的繁体字编码方案

UTF-8:最多用3个子节表示一个字符

Unicode:国际标准码,融合了多种文字,所有的文字都用两个子节来表示,Java语言使用的就是该码表

常用转码方式

1 base64                          byte[] compressed = new sun.misc.BASE64Decoder().decodeBuffer(compressedStr);

2 URLEncoder                 str = URLEncoder.encode(str, GZIP_ENCODE_UTF_8);

3  默认是ISO-8859-1        byte[] strArry = str.getBytes();

4  设置用UTF-8解码         byte[] strArry = str.getBytes("utf-8");

5 确认前后端解码格式一样 

1 在我们Java中定义了一个String,其编码方式是啥?

    字符串实际上就是一个char数组。那么Char的编码,其实就是字符串的编码。那么Char是什么编码呢?Java中的String默认使用的是Unicode编码。

    Unicode是一中编码,所谓的编码就是一个编号到字符的一种映射关系,就仅仅是一对一的映射关系而已。

 

2 编码和编码格式的区别是什么?

    1.Unicode 是一种编码,所谓的编码就是一个编号(数字)到字符的一种映射关系,就仅仅是一种一对一的映射关系而已。

    2. GBK、UTF-8是一种编码格式,是用来序列化或存储上述的(编号或者数字)的一种“格式”.

    编码和编码格式:*java的String使用的编码的Unicode,当String存在于内存中的时候,是“只有编码没有编码格式的”,所以java程序中的任何String对象,说它是GBK或者UTF-8都是错的。String在内存中是不存在编码格式*的,它只是一个Unicode的一个字符而已。

    当字符串需要在网络中传输或者要被写入文件的是时候,就需要编码格式了。乱码的问题也因此出现了。

GBK 和 UTF-8:GBK 和 UTF-8 都是用来序列化或存储 Unicode 编码的数据的,但是分别是2中不同的格式,他们都是 Unicode 的实现方式。

    ASCII码 和 Unicode:ASCII 和 Unicode一样也是一种编码,只不过这两种编码能编码的范围不同,Unicode 能编码的范围要更大一些,几乎能覆盖现存的所有字符。

 

3 按字节

我们一般都是使用InputStream.read()方法在数据流中读取字节(read()每次都只读取一个字节,效率非常慢,我们一般都是使用read(byte[])),然后保存在一个byte[]数组中,最后转换为String。在我们读取文件时,读取字节的编码取决于文件所使用的编码格式,而在转换为String过程中也会涉及到编码的问题,如果两者之间的编码格式不同可能会出现问题。例如存在一个问题test.txt编码格式为UTF-8,那么通过字节流读取文件时所获得的数据流编码格式就是UTF-8,而我们在转化成String过程中如果不指定编码格式,则默认使用系统编码格式(GBK)来解码操作,由于两者编码格式不一致,那么在构造String过程肯定会产生乱码,如下:

File file = new File("C:\\test.txt");

        InputStream input = new FileInputStream(file);

        StringBuffer buffer = new StringBuffer();

        byte[] bytes = new byte[1024];

        for(int n ; (n = input.read(bytes))!=-1 ; ){

            buffer.append(new String(bytes,0,n));

        }

        System.out.println(buffer);

要想不出现乱码,在构造String过程中指定编码格式,使得编码解码时两者编码格式保持一致即可:

buffer.append(new String(bytes,0,n,"UTF-8"));

4 按字符

其实字符流可以看做是一种包装流,它的底层还是采用字节流来读取字节,然后它使用指定的编码方式将读取字节解码为字符。在java中Reader是读取字符流的超类。所以从底层上来看按字节读取文件和按字符读取没什么区别。在读取的时候字符读取每次是读取留个字节,字节流每次读取一个字节。

5 字节&字符转换

字节转换为字符一定少不了InputStreamReader。API解释如下:InputStreamReader 是字节流通向字符流的桥梁:它使用指定的 charset 读取字节并将其解码为字符。它使用的字符集可以由名称指定或显式给定,或者可以接受平台默认的字符集。 每次调用 InputStreamReader 中的一个 read() 方法都会导致从底层输入流读取一个或多个字节。要启用从字节到字符的有效转换,可以提前从底层流读取更多的字节,使其超过满足当前读取操作所需的字节。API解释非常清楚,InputStreamReader在底层读取文件时仍然采用字节读取,读取字节后它需要根据一个指定的编码格式来解析为字符,如果没有指定编码格式则采用系统默认编码格式。

String file = "C:\\test.txt";

         String charset = "UTF-8";

         // 写字符换转成字节流
         FileOutputStream outputStream = new FileOutputStream(file);
         OutputStreamWriter writer = new OutputStreamWriter(outputStream, charset);

         try {
            writer.write("我是 cm");
         } finally {
            writer.close();
         }

         // 读取字节转换成字符
         FileInputStream inputStream = new FileInputStream(file);
         InputStreamReader reader = new InputStreamReader(
         inputStream, charset);
         StringBuffer buffer = new StringBuffer();
         char[] buf = new char[64];
         int count = 0;

         try {
            while ((count = reader.read(buf)) != -1) {
                buffer.append(buf, 0, count);
            }
         } finally {
            reader.close();
         }
         System.out.println(buffer);

首先我们看下面这段简单的代码

        String s = "我是 cm";
         byte[] bytes = s.getBytes();
         String s1 = new String(bytes,"GBK");
         String s2 = new String(bytes);

在这段代码中我们看到了三处编码转换过程(一次编码,两次解码)。先看String.getTytes():

public byte[] getBytes() {
        return StringCoding.encode(value, 0, value.length);
    }

内部调用StringCoding.encode()方法操作:

static byte[] encode(char[] ca, int off, int len) {
        String csn = Charset.defaultCharset().name();
        try {
            // use charset name encode() variant which provides caching.
            return encode(csn, ca, off, len);
        } catch (UnsupportedEncodingException x) {
            warnUnsupportedCharset(csn);
        }

        try {
            return encode("ISO-8859-1", ca, off, len);
        } catch (UnsupportedEncodingException x) {
            // If this code is hit during VM initialization, MessageUtils is
            // the only way we will be able to get any kind of error message.
            MessageUtils.err("ISO-8859-1 charset not available: "
                             + x.toString());
            // If we can not find ISO-8859-1 (a required encoding) then things
            // are seriously wrong with the installation.
            System.exit(1);
            return null;
        }
    }

encode(char[] paramArrayOfChar, int paramInt1, int paramInt2)方法

首先调用系统的默认编码格式,如果没有指定编码格式则默认使用ISO-8859-1编码格式进行编码操作,进一步深入如下:

String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;

同样的方法可以看到new String 的构造函数内部是调用StringCoding.decode()方法:

public String(byte bytes[], int offset, int length, Charset charset) {
        if (charset == null)
            throw new NullPointerException("charset");
        checkBounds(bytes, offset, length);
        this.value =  StringCoding.decode(charset, bytes, offset, length);

    }

 

decode方法和encode对编码格式的处理是一样的。

对于以上两种情况我们只需要设置统一的编码格式一般都不会产生乱码问题

发布了38 篇原创文章 · 获赞 26 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/sdrfengmi/article/details/87798259