13Java编码解码学习笔记

              Java编码解码学习笔记

1 什么是编码与解码

​ 电脑是由电路板组成,电路板里面集成了无数的电阻和电容,交流电经过电容的时候,电压比较低,记为低电平,用0表示;

交流电经过电阻的时候,电压比较高,记为高电平,用1来表示;所以,每一个1和0在计算机中被称为位,也就是bit位。

然而,如果使用一个位来表示计算机中的最小存储单元,那么我们存储单元只能存储0或者1,存储范围太小了,

所以我们规定用8个bit位作为一组来表示计算机的最小存储单元。8个位每个位上能存储0或1,

则byte的存储范围是00000000-11111111(换算成整数即0-255)。这个最小存储单元就是byte字节。

​ 计算机的底层只能存储0和1,如果是日常生活中遇到的数字比如127,这个可以通过10进制和二进制的转换从而让计算机存储

011111111,但是如果计算机存储类似汉子、英文字符、符号字符等内容,是如何存储的呢?

image-20220109143139802

根据上图解释说明,计算机提供了很多的编码表记录了字符和数字的一一对应关系,

编码就是把字符对应编码表中的码值存储在电脑中,

而解码则是把码值在编码表中的对应的字符展现出来。

注意:计算机中存储一个数,是用二进制来表示的,比如存储127,那么计算机的底层是0111 1111,人看这些二进制的数值通常都是眼花缭乱的,如何方便而规整的表示这些二进制数呢,不妨引入十六进制。二进制换算成十六进制,则是每四位为一组转换为16进制即可,比如0111 1111 这个数前4位 0111 转换为7,后4位转换为F,则最终的16进制数是7F,一般繁琐的二进制数使用十六进制来表示会比较方便规整,所以人们习惯用十六进制数来表示码值。

计算机提供了哪些编码表呢?

2 常见的编码表

2.1 ASCII

世界上虽然有各种各样的字符,但计算机发明之初没有考虑那么多,基本上只考虑了美国的需求,美国大概只需要128个字符,美国就规定了这128个字符的二进制表示方法,这个方法是一个标准,称为ASCII编码,全程是American Standard Code for Information interchange,美国信息互换标准代码。128个字符用7个位刚好可以表示,计算机存储的最小单元是byte,即8位,ASCII码中最高位设置为0,用剩下的7位表示字符。这7位可以看做数字0到127,ASCII码规定了从0到127个,每个数字代表什么含义。我们先来看数字32到126的含义,如下图所示,除了中文之外,我们平常用的字符基本都涵盖了,键盘上的字符大部分也都涵盖了。

ASCII值控制字符ASCII值控制字符ASCII值控制字符ASCII值控制字符
0NUT32(space)64@96
1SOH33!65A97a
2STX34"66B98b
3ETX35#67C99c
4EOT36$68D100d
5ENQ37%69E101e
6ACK38&70F102f
7BEL39,71G103g
8BS40(72H104h
9HT41)73I105i
10LF42*74J106j
1VT43+75K107k
12FF44,76L108l
13CR45-77M109m
14SO46.78N110n
15SI47/79O111o
16DLE48080P112p
17DCI49181Q113q
18DC250282R114r
19DC351383S115s
20DC452484T116t
21NAK53585U117u
22SYN54686V118v
23TB55787W119w
24CAN56888X120x
25EM57989Y121y
26SUB58:90Z122z
27ESC59;91[123{
28FS60<92/124|
29GS61=93]125}
30RS62>94^126`

数字32到126表示的这些字符都是可打印字符,0到31和127表示一些不可以打印的字符,这些字符一般用于控制目的,这些字符中大部分都是不常用的。

2.2 ISO-8859-1

扩展的ASCII表,西欧编码 一个字节存储一个字符

扩展的是拉丁文,不是中文汉字。主要是给拉丁文语言用。

西欧 是拉丁文,字符也是比较少的。

ISO-8859-1又称Latin-1,它也是使用了一个字节表示一个字符,因为西欧的文字也都是字母拼接,只不过不是26个英文字母罢了,

其中0到127与ASCII一样,128到255规定了不同的含义。

在128到255中,128到159不表示一些控制字符,这些字符也不常用,这里不介绍了,

160到255表示一些西欧字符,如下图所示:

2.3 GB2312

中国编码格式 7000多个,不包含罕见字,不包含繁体字。

​ 美国和西欧字符用一个字节就够了,但中文显然是不够用的。中文第一个标准是GB2312。GB2312标准主要针对的是简体中文常见字符,包括约7000个汉字,不包括一些罕见词,不包括繁体字。GB2312固定使用两个字节表示汉字,在这两个字节中,最高位都是1,如果是0,就认为是ASCII字符。

在这两个字节中,其中第一个字节范围是1010 0001(十进制161) -1111 0111(十进制247),

第二个字节范围是1010 0001(十进制161)-1111 1110(十进制254)。

比如:“贤哥”的GB2312编码是

CF,CDB8,E7

2.4 GBK

中国编码格式 21000汉字,其中包括繁体字,不含少数民族。

用2个字节表示。 Windows简体中文系统 用的是GBK编码。

​ GBK建立在GB2312的基础上,向下兼容GB2312,也就是说,GB2312编码的字符的二进制表示,

在GBK编码里是完全一样的。GBK增加了一万四千多个汉字,共计21000汉字,其中包括繁体字。

GBK同样使用固定的两个字节表示,其中第一个字节范围是1000 0001(十进制129)-1111 1110(十进制254),

第二个字节范围是0100 1111(十进制64) - 0111 1110(十进制126)和1000 0000(十进制128) - 1111 1110(十进制254)。

需要注意的是,第二个字节是从64位开始的(64属于byte正数范围,和ASCII的编码重合了),也就是说,第二个字节最高位可能为0,

那怎么会知道它是汉子的一部分,还是一个ASCII字符呢?
其实很简单,因为汉子是用固定两个字节表示的,在解析二进制流的时候,如果第一个字节的最高位是1,那么就将下一个字节读进来一起解析为一个汉子,而不用考虑它的最高位,解析完后,跳到第一个字节继续解析。

ANSI:系统默认编码

2.5 GB18030

中国编码格式 4个字节

​ GB18030向下兼容GBK,增加了五万五千多个字符,共七万六千多个字符。包含了很多少数民族字符,以及中日韩统一字符。用两个字节表示不了GB18030中的所有字符,GB18030使用变长编码,有的字符是两个字节,有的是四个字节。在两个字节编码中,字节表示范围与GBK一样。

在四个字节编码中:

第一个字节的值从1000 0001(十进制129)到1111 1110(十进制254),第二个字节的值从0011 0000(十进制48) 到 0011 1001(十进制57),

第三个字节的值从1000 0001(十进制129) 到1111 1110(十进制254),第第个字节的值从0011 0000(十进制48) 到0011 1001(十进制57)。

​ 解析二进制时,如何知道是两个字节还是四个字节表示一个字符呢?很简单,看第二个字节的范围,如果是48到57就是四个字节表示,因为两个字节编码中的第二个字节都比这个。

​ 所有这样综合说明GB18030兼容GBK,兼容GB2312,兼容ASCII,

​ 但是GB18030,GBK,GB2312这些编码和ISO-8859-1是不兼容的。

2.6 Big5

Big5是针对繁体中文的,广泛用在台湾香港等地。Big5包括1万3千多个繁体字,和GB2312类似,一个字符同样固定两个字节表示。

在这两个字节中,

第一个字节范围1000 0001(十进制129)到1111 1110(十进制254),

第二个字节范围是0111 0000(十进制54) - 0111 1110(十进制126) 和 1010 0001(十进制161)-1111 1110(十进制254)。

Big5和GB18030,GBK,GB2312不兼容,如果已经理解了上文,其实你就能理解为什么Big5和GB的一个编码为什么不兼容了。

2.7 编码表汇总

我们简单汇总一下上面的内容。

ASCII码是基础,一个字节表示,最高位设为0,其他7位表示128个字节。其他编码都是兼容ASCII的,最高位使用1来进行区分。

西欧主要使用Windows1252,使用一个字节,增加了额外128个字符。

​ 中文大陆地区的三个主要编码GB2312,GBK,GB18030,有时间先后关系,表示的字符数越来越多,且后面的兼容前面的,

GB2312和GBK都是用两个字节表示,而GB18030则使用两个或四个字节表示。

香港台湾地区的主要编码是Big5。

如果文本里的字符都是ASCII码字符,那么采用以上所说的,任一编码方式都是一样的,不会乱码。

但如果有高位为1的字符,出了GB2312/GBK/GB18030外,其他编码都是不兼容的,

比如,Windows-1252和中文的各种编码是不兼容的,

​ 即使Big5和GB18030都能表示繁体字了,其表示方式也是不一样的,而这就会出现所谓的乱码。

2.8 乱码与兼容

兼容:GB2312/GBK/GB18030 ASCII是兼容的,比如我们文本里面的a字符,使用这四种码表任何一种都是可以正常显示的。

​ windows-1252和ISO-8859-1和ASCII是兼容的。 西欧

​ Big5和ASCII是兼容的。

​ 但是西欧编码和Big5以及GB系列的编码,他们相互之间是不兼容的,也就是 同样的码值在三种编码表中显示的内容是不一样的。

兼容示意图:

image-20220109163320464

乱码示意图:

image-20220109163417081

2.9 Unicode

以上我们介绍了中文和西欧的字符与编码,但世界上还有很多的国家的字符,每个国家的各种计算机厂商都对自己常用的字符进行编码,在编码的时候基本忽略了别的国家的字符和编码,甚至忽略了同一个国家的其他计算机厂商,这样造成的结果就是出现了太多的编码,且互相不兼容。

世界上所有的字符能不能统一编码呢?可以,这就是Unicode.

Unicode做了一件事,就是给世界上所有字符都分配了一个唯一的数字编号,这个编号范围从0x000000到0x10FFFF,包括110多万。但大部分常用字符都在0x0000到0xFFFF之间,即65536个数字之内。每个字符都有一个Unicode编号,这个编号一般写成16进制,在前面加U+。大部分中文的编号范围在U+4E00到U+9FA5,例如,“贤”的unicode是U+8D24.

​ Unicode就做了这么一件事,就是给所有字符分配了唯一数字编号。它并没有规定这个编号怎么对应到二进制表示,这是与上面介绍的其他编码不同的,其他编码都既规定了能表示哪些字符,又规定了美国字符对应的二进制是什么,而Unicode本身只规定了每个字符的数字编号是多少。

那编号怎么对应到二进制表示呢?有多种方案,有UTF-8,UTF-16,UTF-32。

2.9.1 UTF-32

这个最简单,就是字符编号的整数二进制形式,四个字节。

每个字符都用四个字节表示,非常浪费空间,实际采用的也比较少。

2.9.2 UTF-16

注意:UTF-8常用于系统内部编码,我们平常说的“Unicode编码是2个字节”这句话,其实是因为Windows系统默认的Unicode编码就是UTF-16,在常用基本字符2个字节的编码方式已经够用导致的误解。其实是可变长度的。在没有特殊说明的情况下,常说的Unicode编码可以理解为UTF-16编码。

​ UTF-8比UTF-32节省了很多空间,

​ 但是任何一个字符都至少需要两个字节表示,对于美国和西欧国家而言,还是很浪费的,于是UTF-8出现了。

2.9.3 UTF-8

UTF-8就是使用变长字节表示,每个字符使用的字节个数与其Unicode编号的大小有关,编号小的使用的字节就少,编号大的使用的字节就多,使用的字节个数从1到4个不等。

具体来说,各个Unicode编号范围对应的二进制格式如下表所示:

Unicode(十六进制)UTF-8字节流(二进制)
000000-00007F0xxxxxxx 128,就是ASCII一样 1个字节表示
000080-0007FF110xxxxx 10xxxxxx 2个字节表示
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx 中国汉字一般都落在这个范围 3个字节表示
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 4个字节表示

图中的x表示可以用的二进制位,而每个字节开头的1或0是固定的。

小于128位,编码与ASCII码一样,最高位是0。其他编号第一个字节有特殊含义,最高位有几个连续的1,表示一共用几个字节表示,

而其他字节都可以10开头。4字节模板有21个x,即可以容纳21位二进制数字。

Unicode的最大码位0x10FFFF也只有21位。

一个系统,要符合能被全球访问的要求,所以只能在UTF-8和UTF-32/UTF-16三种编码中选其中一种。

注意:UTF-8和UTF-32/UTF-16不同的地方是UTF-8是兼容ACSII的对大部分中文而言,一个中文字符需要用三个字节表示,UTF-8的优势是网络上数据传输英文字符只需要1个字节,可以节省带宽资源。

所以当前大部分的网络应用都使用UTF-8编码因为网络应用的代码编写全部都是使用的英文编写,占据空间小,网络传输速度快

2.10 乱码的原因和可逆性

乱码产生的根源一般情况下可以归集为三个方面:

​ 1.编码引起的乱码 —不可逆

​ 2.解码引起的乱码 —可逆

​ 3.缺少某种字体库引起的乱码(这种情况需要用户安装对应的字体库)。 —可逆

其中大部分乱码问题是由不合适的解码方式造成的。

image-20220109204137233

乱码可逆情况:

​ 其中缺少字体,只需要安装对应的字体库即可解决乱码。比如Windows系统在C:\Windows\Fonts目录下会有安装好的字体库列表。

安装字体库比较简单,下载后解压,然后复制到对应系统的Fonts目录下。

​ 解码方式和编码方式不一致的情况,只需要解码方式和编码方式一致即可让乱码恢复。

乱码不可逆的情况:

​ GBK编码不支持这几个字符“吉”,如果在一个GBK编码的文件中,写入“吉”这些字符,那么他们就会变成??,对应的码值是3F,

这样的情况就没有办法恢复,因为“吉”的本来编码变成了两个3F(即两个问号),无论如何也不能恢复过来了。

3 char字符

在Java内部进行字符处理时,采用的是Unicode,具体编码格式是UTF-16BE。简单回顾一下,UTF-16使用两个或者四个字节表示一个字符。

Unicode编号范围在65536以内的占两个字节,超出范围的占四个字节。

char本质上是一个固定占用两个字节的无符号正整数,这个正整数对应Unicode编号,用来表示那个Unicode编码对应的字符。

由于固定占用两个字节,char只能表示Unicode编号在65536以内的字符,而不能表示超出范围的字符。

那超出范围的字符怎么表示呢?只能使用String类来表示,例如汉子“吉”的Unicode码点为0x20887,该码点显然超出了65535,所以只能用String表示,而当粘贴到代码中时,自动转换为两个字符“\uD842\uDFB7”。

char 本质 固定的两个字节

UTF-16 基本面 两个字节表示 如果是辅助码的话 用4个字节表示

char 表示不了辅助面的字符,于是String出来了。

4 String类

4.1 编码的方法

4.1.1 getBytes()方法

package com.tangguanlin.encoding;
/**
 * 说明:不指定编码格式
 * 作者:汤观林
 * 日期:2022年01月09日 21时
 */
public class EncodingTest1 {
    public static void main(String[] args) {

        String str = "黑马";
        byte[] bytes = str.getBytes();//进行编码  -23 -69 -111 -23 -87 -84  utf-8:一个汉子3个字节,共6个字节
        for(byte ebyte:bytes){
            System.out.println(ebyte);
            int temp = ebyte;
            String toBinaryString = Integer.toBinaryString(temp);
            System.out.println(toBinaryString);
        }
    }
}

运行结果:

-23
11111111111111111111111111101001
-69
11111111111111111111111110111011
-111
11111111111111111111111110010001
-23
11111111111111111111111111101001
-87
11111111111111111111111110101001
-84
11111111111111111111111110101100

4.1.2 getBytes(String charsetName)方法

package com.tangguanlin.encoding;
import java.io.UnsupportedEncodingException;
/**
 * 说明:指定编码格式
 * 作者:汤观林
 * 日期:2022年01月09日 21时
 */
public class EncodingTest1 {
    public static void main(String[] args) throws UnsupportedEncodingException {

        String str = "黑马";

        //指定UTF-8编码  
        byte[] bytes = str.getBytes("UTF-8");//进行编码  -23 -69 -111 -23 -87 -84  utf-8:一个汉子3个字节,共6个字节
        for(byte ebyte:bytes){
            System.out.println(ebyte);
            int temp = ebyte;
            String toBinaryString = Integer.toBinaryString(temp);
            System.out.println(toBinaryString);
        }

        System.out.println("===================================");

        //指定GBK编码
        byte[] bytes1 = str.getBytes("GBK"); //-70 -38 -62 -19 GBk编码一个汉子 2个字节存储
        for(byte ebyte:bytes1){
            System.out.println(ebyte);
            int temp = ebyte;
            String toBinaryString = Integer.toBinaryString(temp);
            System.out.println(toBinaryString);
        }
    }
}

运行结果:

-23
11111111111111111111111111101001
-69
11111111111111111111111110111011
-111
11111111111111111111111110010001
-23
11111111111111111111111111101001
-87
11111111111111111111111110101001
-84
11111111111111111111111110101100
===================================
-70
11111111111111111111111110111010
-38
11111111111111111111111111011010
-62
11111111111111111111111111000010
-19
11111111111111111111111111101101

4.2 解码的方法

4.2.1 new String(byte[] bytes)

package com.tangguanlin.encoding;
import java.io.UnsupportedEncodingException;
/**
 * 说明:不指定编码格式
 * 作者:汤观林
 * 日期:2022年01月09日 22时
 */
public class EncodingTest2 {
    public static void main(String[] args) throws UnsupportedEncodingException {

        byte[] bytes = {-23,-69,-111,-23,-87,-84}; //黑马:UTF-8 [ -23 -69 -111 -23 -87 -84]
        String s = new String(bytes);  //解码  用的UTF-8 编码
        System.out.println(s); //黑马
    }
}

运行结果:

黑马

4.2.2 new String(byte[] bytes,String charsetName)

package com.tangguanlin.encoding;
import java.io.UnsupportedEncodingException;
/**
 * 说明:指定解码格式
 * 作者:汤观林
 * 日期:2022年01月09日 22时
 */
public class EncodingTest2 {
    public static void main(String[] args) throws UnsupportedEncodingException {

        byte[] bytes = {-23,-69,-111,-23,-87,-84}; //黑马:UTF-8 [ -23 -69 -111 -23 -87 -84]
        String s = new String(bytes,"UTF-8");  //解码  用的UTF-8 编码
        System.out.println(s); //黑马

        //指定具体的解码格式
        byte[] bytes1 = {-70,-38,-62,-19};  //黑马:GBK [-70 -38 -62 -19]
        String s1 = new String(bytes1, "GBK"); //
        System.out.println(s1);
    }
}

运行结果:

黑马
黑马

4.3 乱码的可逆问题

package com.tangguanlin.encoding;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
/**
 * 说明:乱码可逆的情况
 * 作者:汤观林
 * 日期:2022年01月09日 22时
 */
public class EncodingTest3 {
    public static void main(String[] args) throws UnsupportedEncodingException {

        java.lang.String str = "黑马"; //黑马:GBK [-70 -38 -62 -19]
        byte[] gbks = str.getBytes("GBK");
        System.out.println(Arrays.toString(gbks));

        String s1 = new String(gbks, "UTF-8");
        System.out.println(s1);

        String s2 = new String(gbks, "GBK");
        System.out.println(s2);
    }
}

运行结果;

[-70, -38, -62, -19]
����
黑马

4.4 乱码的不可逆问题

package com.tangguanlin.encoding;
import java.util.Arrays;
/**
 * 说明:乱码不可逆问题
 * 作者:汤观林
 * 日期:2022年01月09日 22时
 */
public class EncodingTest4 {
    public static void main(String[] args) throws Exception {

        String str = "黑马" ;
        byte[] bytes = str.getBytes("ISO-8859-1"); //[63, 63]
        System.out.println(Arrays.toString(bytes));

        String s1 = new String(bytes, "ISO-8859-1"); //??
        System.out.println(s1);

        String s2 = new String(bytes, "GBK"); //??
        System.out.println(s2);

        String s3 = new String(bytes, "UTF-8"); //??
        System.out.println(s3);
    }
}

运行结果:

[63, 63]
??
??
??

4.5 ISO-8859-1编码的妙用

package com.tangguanlin.encoding;
import java.util.Arrays;
/**
 * 说明:ISO-8859-1的妙用
 * 作者:汤观林
 * 日期:2022年01月09日 22时
 */
public class EncodingTest5 {
    public static void main(String[] args) throws Exception {

        String str = "黑马" ;
        byte[] bytes = str.getBytes("GBK"); //黑马:GBK [-70 -38 -62 -19]
        System.out.println(Arrays.toString(bytes));

        String s1 = new String(bytes, "ISO-8859-1"); //一个字节,对应一个字符  任何字符都能找到对应
        System.out.println(s1); //ºÚÂí

        byte[] bytes1 = s1.getBytes("ISO-8859-1");
        System.out.println(Arrays.toString(bytes1));  //[-70, -38, -62, -19]

        String s2 = new String(bytes1, "GBK");
        System.out.println(s2); //黑马
    }
}

运行结果:

[-70, -38, -62, -19]
ºÚÂí
[-70, -38, -62, -19]
黑马

5 IO流-字符流

5.1 InputStreamReader

字符输入流的原理:

image-20220109235734892

案例:

a.txt

image-20220110001813082

代码:

package com.tangguanlin.encoding;
import java.io.*;
/**
 * 说明:字符输入流乱码原理
 * 作者:汤观林
 * 日期:2022年01月09日 23时
 */
public class EncodingTest6 {
    public static void main(String[] args) throws IOException {
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("a.txt"), "GBK");
        int ch;
        while ((ch=inputStreamReader.read())!=-1){
            System.out.println((char)ch);
        }
        inputStreamReader.close();
    }
}

运行结果:

涓

浗

字符输入流乱码原理:

image-20220109235617503

5.2 OutputStreamReader

字符输出流的原理:

image-20220110002104889

代码:

package com.tangguanlin.encoding;
import java.io.*;
/**
 * 说明:字符输出流乱码原理
 * 作者:汤观林
 * 日期:2022年01月09日 23时
 */
public class EncodingTest7 {
    public static void main(String[] args) throws IOException {
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"), "GBK");
        outputStreamWriter.write("中国");
        outputStreamWriter.flush();  //刷新  写出去
        outputStreamWriter.close();
    }
}

运行结果:

image-20220110001705658

字符输出流乱码原理:

image-20220110002200437

5.3 字符流复制文件

字符流复制文本乱码因素

4个因素:

源文件编码 -----------------------编码要一致------------------------------Reader缓冲区编码

Writer缓冲区编码---------------编码要一致------------------------------目标文件编码

代码:

package com.tangguanlin.encoding;
import java.io.*;
/**
 * 说明:字符流复制文本文件乱码原理
 * 作者:汤观林
 * 日期:2022年01月09日 23时
 */
public class EncodingTest7 {
    public static void main(String[] args) throws IOException {
        //编码改为GBK才可以
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("a.txt"), "UTF-8");
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("b.txt"), "UTF-8");
        int ch;
        while ((ch = inputStreamReader.read())!=-1){
            outputStreamWriter.write(ch);
        }
        inputStreamReader.close();
        outputStreamWriter.close();
    }
}

运行结果:

�й�

字符流复制文本文件乱码原理:

image-20220110003637051

5.4 字符流复制图片

代码:

package com.tangguanlin.encoding;
import java.io.*;
/**
 * 说明:字符流复制图片乱码原理
 * 作者:汤观林
 * 日期:2022年01月09日 23时
 */
public class EncodingTest8 {
    public static void main(String[] args) throws IOException {
        //编码改成 ISO-8859-1 才能复制
        InputStreamReader inputStreamReader = new InputStreamReader(new FileInputStream("D:\\11.jpg"), "UTF-8");
        //编码改成 ISO-8859-1 才能复制
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream("D:\\22.jpg"), "UTF-8");
        int ch;
        while ((ch = inputStreamReader.read())!=-1){
            outputStreamWriter.write(ch);
        }
        inputStreamReader.close();
        outputStreamWriter.close();
    }
}

运行结果:

image-20220110005716803

字符流复制图片乱码原理:

image-20220110010102120

解决方案原理:

image-20220110010148571

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值