2021-06-20

小白都能懂得的编码与解码的详细讲解(附python文件读写)

编码

先来看编码。编码的本质就是让只认识0和1的计算机,能够理解我们人类使用的语言符号,并且将数据转换为二进制进行存储和传输。

这种从人类语言到计算机语言转换的形式,就叫做编码表,它让人类语言和计算机语言能够一一对应起来。

要了解编码,我们还得先来聊聊二进制。由于有二进制,0和1这两个数字才能像“太极生两仪,两仪生四象,四象生八卦”一样,涵盖容纳世间所有的信息。

二进制

说起二进制,用烽火这种古老的信息传递形式,来比喻说明计算机是怎么传输和存储数据的。

假设我们都是看守城墙的小兵,你在烽火台A上,我在烽火台B上,只要你那边来了敌人,你就点着烽火台通知我。

如果只有一个烽火台,那么只有“点着火”和“没点火”两种状态,这就像电子元件里“通电”和“没通电”的状态,所以只有0和1.

但是你光告诉我来敌人还不够啊,还得告诉我敌人的数量有多少,让我好call齐兄弟做好准备。现在问题是你要怎么通知我敌人的数量呢?

所以,我们之间就约定了特别的“暗号”,来通知彼此敌情。
在这里插入图片描述
现在有两座烽火台,右边为第1座,左边为第2座。我们约定,当没有烽火台被点着的时候,表示没有敌人(00);只点着第一座烽火台的时候,表示来了一个敌人(01);只点着第二座烽火台的时候,表示来了2个敌人。(10,逢二进一)

当两座烽火台都被点着的时候(11),就表示来了3个人。
也就是这样的对应关系:
在这里插入图片描述
所以两个二进制位可以表示十进制的0,1,2,3四种状态。

现在你应该可以听得懂这个笑话:世界上有10种人,懂二进制和不懂二进制的。

我们继续往下推,当有三座烽火台的时候,我们可以表示0~7八种状态(也就是2的3次方)。
在这里插入图片描述
以此类推,当有八座烽火台的时候,我们就能表示2的8次方,也就是256种状态,它由8个0或1组成。

00000000 表示状态0: 烽火全暗,一个敌人没有,平安无事,放心睡觉。
11111111 表示状态255:烽火全亮,来了255个敌人。起来打啊!

用来存放一位0或1,就是计算机里最小的存储单位,叫做【位】,也叫【比特】(bit)。我们规定8个比特构成一个【字节】(byte),这是计算机里最常用的单位。
在这里插入图片描述
bit和byte长得有点像,可别混淆!1 byte = 8 bit,也就是1字节等于8比特。
这些计算机单位,可与我们息息相关,你的手机“流量”,就是这么计算的:
在这里插入图片描述

编码表

计算机一开始发明的时候,只是用来解决数字计算的问题。后来人们发现,计算机还可以做更多的事,正所谓能力越大,责任越大。但由于计算机只识“数”,因此人们必须告诉计算机哪个数字来代表哪个特定字符。

于是除了0、1这些阿拉伯数字,像a、b、c这样的52个字母(包括大小写),还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,理论上每个人都可以有自己的一套规则(这就叫编码)。

但大家如果想要互相沟通而不造成混乱,就必须使用相同的编码规则。如果使用了不同的编码规则,那就会彼此读不懂,这就是“乱码”的由来。
在这里插入图片描述
为了避免乱码,一段世界历史就此启动。

一开始,是美国首先出台了ASCII编码(读音:/ˈæski/),统一规定了常用符号用哪些二进制数来表示。因为英文字母、数字再加上其他常用符号,也就100来个,因此使用7个比特位(最多表示128位)就够用了,所以一个字节中被剩下的那个比特位就被默认为0。

再后来呢,这套编码表传入欧洲,才发现这128位不够用啊。比如说法语字母上面还有注音符,这个怎么区分?得!把最后一个比特位也编进来吧。因此欧洲普遍使用一个全字节(8个比特位)进行编码,最多可表示256位,至此,一个字节就用满了!
但是前面的状态0-127位可以共用,但从状态128到255这一段的解释就完全乱套了,比如135在法语,希伯来语,俄语编码中完全是不同的符号。

当计算机漂洋过海来到中国后,问题又来了,计算机完全不认识博大精深的中文,当然也没法显示中文;而且一个字节的256位都被占满了,但中国有10万多个汉字,256位连塞牙缝都不够啊。

于是中国科学家自力更生,重写了一张编码表,也就是GB2312,它用2个字节,也就是16个比特位,来表示绝大部分(65535个)常用汉字。后来,为了能显示更多的中文,又出台了GBK标准。

不仅中国,其他国家也都搞出自己的一套编码标准,这样的话地球村村民咋沟通?日本人发封email给中国人,两边编码表不同,显示的都是乱码。

为了沟通的便利,Unicode(万国码)应运而生,这套编码表将世界上所有的符号都纳入其中。每个符号都有一个独一无二的编码,现在Unicode可以容纳100多万个符号,所有语言都可以互通,一个网页上也可以显示多国语言。

看起来皆大欢喜。但是!问题又来了,自从英文世界吃上了Unicode这口大锅饭,为迁就一些占用字节比较多的语言,英文也要跟着占两个字节。比如要存储A,原本00010001就可以了,现在偏得用两个字节:00000000 00010001才行,这样对计算机空间存储是种极大的浪费!

基于这个痛点,科学家们又提出了天才的想法:UTF-8(8-bit Unicode Transformation Format)。它是一种针对Unicode的可变长度字符编码,它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度,而当字符在ASCII码的范围时,就用一个字节表示,所以UTF-8还可以兼容ASCII编码。

Unicode与UTF-8这种暧昧的关系一言以蔽之:Unicode是内存编码的规范,而UTF-8是如何保存和传输Unicode的手段。

将上述这段波澜壮阔、分久必合的编码史浓缩成一个表格表示,就是:
在这里插入图片描述
人类语言千变万化,我们有《新华字典》《牛津英语字典》这样的辞书来记录和收纳。可以说,这些编码表就是计算机世界的字典辞书,它们同样也是人类智慧的结晶。

这里,再顺便介绍下八进制和十六进制

因为二进制是由一堆0和1构成的,过长的数字对于人的阅读有很大障碍,为了解决这一问题,也减少书写的复杂性,我们又引入了八进制和十六进制。

为什么偏偏是16或8进制?2、8、16,分别是2的1次方、3次方、4次方。这一点使得三种进制之间可以非常直接地互相转换。

8进制是用0,1,2,3,4,5,6,7;16进制是用0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f来表示。比如说,字母K在ASCII编码表用不同进制表示的话是这样的:(并不需要知道具体的转换规则)
在这里插入图片描述
接下来,介绍几种编码方案在当前的使用情况。

第0,计算机是有自己的工作区的,这个工作区被称为“内存”。数据在内存当中处理时,使用的格式是Unicode,统一标准。
在这里插入图片描述
在Python3当中,程序处理我们输入的字符串,是默认使用Unicode编码的,所以你什么语言都可以输入。

第1,数据在硬盘上存储,或者是在网络上传输时,用的是UTF-8,因为节省空间。但你不必操心如何转换UTF-8和Unicode,当我们点击保存的时候,程序已经“默默地”帮我们做好了编码工作。

第2,一些中文的文件和中文网站,还在使用GBK,和GB2312。
基于此,有时候面对不同编码的数据,我们要进行一些操作来实现转换。这里就涉及接下来要讲的【encode】(编码)和【decode】(解码)的用法。

encode()和decode()

编码,即将人类语言转换为计算机语言,就是【编码】encode();反之,就是【解码】decode()。它们的用法如下图所表示:
在这里插入图片描述
例如下面的代码来运行。1~2行是encode()的用法,3-4行是decode()的用法

print('吴枫'.encode('utf-8'))
print('吴枫'.encode('gbk'))
print(b'\xe5\x90\xb4\xe6\x9e\xab'.decode('utf-8'))
print(b'\xce\xe2\xb7\xe3'.decode('gbk'))

输出为:
在这里插入图片描述
将人类语言编码后得到的结果,有一个相同之处,就是最前面都有一个字母b,比如b’\xce\xe2\xb7\xe3’,这代表它是bytes(字节)类型的数据。

所谓的编码,其实本质就是把str(字符串)类型的数据,利用不同的编码表,转换成bytes(字节)类型的数据。

我们再来区分下字符和字节两个概念。字符是人们使用的记号,一个抽象的符号,这些都是字符:‘1’, ‘中’, ‘a’, ‘$’, ‘¥’ 。

而字节则是计算机中存储数据的单元,一个8位的二进制数。

编码结果中除了标志性的字母b,你还会在编码结果中看到许多\x,你再观察一下这个例子:b’\xce\xe2\xb7\xe3’。

\x是分隔符,用来分隔一个字节和另一个字节。

分隔符还挺常见的,我们在上网的时候,不是会有网址嘛?你经常会看到网址里面有好多的%,它们也是分隔符,替换了Python中的\x。比如像下面这个:
https://www.csdn.net/?spm=1001.2014.3001.5359

i此外,用decode()解码的时候则要注意,UTF-8编码的字节就一定要用UTF-8的规则解码,其他编码同理,否则就会出现乱码或者报错的情况。
比如:

print(b'\xe6\x88\x91\xe7\x88\xb1\xe4\xbd\xa0'.decode('utf-8'))

结果为:
在这里插入图片描述
最后再来看下ASCII编码,它不支持中文,所以来转换一个大写英文字母K。

print('K'.encode('ASCII'))

结果:
在这里插入图片描述
你看到大写字母K被编码后还是K,但这两个K对计算机来说意义是不同的。前者是字符串,采用系统默认的Unicode编码,占两个字节。后者则是bytes类型的数据,只占一个字节。这也验证我们前面所说的编码就是将str类型转换成bytes类型。

读取文件

分三步:打开文件,读取文件,关闭文件

f = open('./1.txt', 'a',encoding='utf-8')
f.write('难念的经\n')
f.close()
f1=open('./1.txt', 'r',encoding='utf-8')
print(f1.read())
f1.close()

参数encoding=‘utf-8’,表示的是返回的数据采用何种编码,一般采用utf-8或者gbk。
OPEN函数的常见用法
这里再顺便补充一个用法,为了避免打开文件后忘记关闭,占用资源或当不能确定关闭文件的恰当时机的时候,我们可以用到关键字with,之前的例子可以写成这样:

#使用with关键字的写法
with open('abc.txt','a',encoding='utf-8') as file1:
#with open('文件地址','读写模式') as 变量名:
    #格式:冒号不能丢
    file1.write('张无忌') 
    #格式:对文件的操作要缩进
    #格式:无需用close()关闭
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值