一、字符编码
(一)储备知识
1.程序运行与三大核心硬件的关系:
应用程序任何操作硬件的请求都需要向操作系统发起系统调用,然后由操作系统去操作硬件。
CPU————从内存中取指运行程序
内存————程序文件加载位置
硬盘————存放程序文件
2.程序运行过程中产生的数据最先存储在内存中。
3.python程序运行的三个步骤:
(1)先启动python解释器;
(2)程序最先存放于硬盘之上,解释器会将py文件的内容当成普通文件从硬盘读入内存,此时没有语法意义;
(3)解释器会执行刚刚读入内存的内容,开始识别python语法。
(二)字符编码介绍
1.什么是字符编码
计算机要想工作必须通电,即用‘电’驱使计算机干活,也就是说‘电’的特性决定了计算机的特性。电的特性即高低电平(人类从逻辑上将二进制数1对应高电平,二进制数0对应低电平),关于磁盘的磁特性也是同样的道理。结论:计算机只认识数字0和1。
很明显,我们平时在使用计算机时,用的都是人类能读懂的字符(用高级语言编程的结果也无非是在文件内写了一堆字符),如何能让计算机读懂人类的字符?
必须经过一个过程:
# 字符----------(标准)----------数字
# 字符编码表:存放的是字符与数字的对应关系。
2.主要的字符编码表
(1)ASCII:
①作用:
只能识别英文字符。
②特点:
采用8bit对应一个英文字符, 8bit = 1Byte。
(2)GBK:
①作用:
可以识别中文字符与英文字符。
②特点:
采用16bit对用字符,该字符可以是英文字符,也可以是中文字符。
(3)Shift-JIS\Euc-kr:
日本、韩国及其他各国都在使用计算机的过程中,制定了相应的字符编码表。
(4)unicode:
①作用:
可以识别万国字符。
②特点:
2Bytes对应一个字符。
# 首先,任意字符与Unicode编码有对应关系。
字符--对应--》unicode格式的数字
|
GBK shift-JIS
# 其次,unicode与任意已有的字符编码也有对应关系。
# 注意:
内存固定使用:unicode
我们可以改变的是从内存写入硬盘采用的编码格式.
(5)utf-8:
①作用:
存储的时候对各国字符进行优化,减少程序I/O次数,提升程序的运行效率。
②特点:
1Bytes对应一个字符,3Bytes对应一个中文字符。
2.字符编码发展的三个阶段
(1)一家独大:
现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII。
ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符。
ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后来为了将拉丁文也编码进了ASCII表,将最高位也占用了。
英文字符--------------内存:ASCII二进制数--------------->硬盘:ASCII二进制数
(2)群雄割据:
为了满足中文和英文,中国人定制了GBK。
GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符。
为了满足其他国家,各个国家纷纷定制了自己的编码。
日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里。
中文英文字符--------------内存:GBK二进制数--------------->硬盘:GBK二进制数
日文英文字符--------------内存:shiftJIS二进制数--------------->硬盘:shiftJIS二进制数
韩文英文字符--------------内存:Euc-Kr二进制数--------------->硬盘:Euc-Kr二进制数
(3)分久必合:
各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。如何解决这个问题呢?
# !!!!!!!!!!!!非常重要!!!!!!!!!!!!
说白了乱码问题的本质就是不统一,如果哪个国家能统一全世界,规定全世界只能使用一种文字符号,然后统一使用一种编码,那么乱码问题将不复存在,很明显,上述的假设是不可能成立的。很多地方或老的系统、应用软件仍会采用各种各样的编码,这是历史遗留问题。于是我们必须找出一种解决方案或者说编码方案,需要同时满足:
# 1、能够兼容万国字符
# 2、与全世界所有的字符编码都有映射关系,这样就可以转换成任意国家的字符编码
这就是unicode(定长),统一用2Bytes代表一个字符,虽然2**16-1=65535,但unicode却可以存放100w+个字符,因为unicode存放了与其他编码的映射关系,准确地说unicode并不是一种严格意义上的字符编码表。
很明显对于通篇都是英文的文本来说,unicode的式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)。
于是产生了UTF-8(可变长,全称Unicode Transformation Format),对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存。
# 总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。
# 过渡阶段
中文英文字符------------内存:unicode=========gbk============>硬盘:GBK二进制数
日文英文字符------------内存:unicode=========shifJIS========>硬盘:shiftJIS二进制数
韩文英文字符------------内存:unicode=========Euc-Kr=========>硬盘:Euc-Kr二进制数
万国字符----------------内存:unicode=========utf-8==========>硬盘:utf-8二进制数
基于目前的现状,内存中的编码固定就是unicode,我们唯一可变的就是硬盘的上对应的字符编码。此时你可能会觉得,那如果我们以后开发软时统一都用unicode编码,那么不就都统一了吗,关于统一这一点你的思路是没错的,但我们不可会使用unicode编码来编写程序的文件,因为在通篇都是英文的情况下,耗费的空间几乎会多出一倍,这样在软件读入内存或写入磁盘时,都会徒增IO次数,从而降低程序的执行效率。因而我们以后在编写程序的文件时应该统一使用一个更为精准的字符编码utf-8(用1Bytes存英文,3Bytes存中文),再次强调,内存中的编码固定使用unicode。
1、在存入磁盘时,需要将unicode转成一种更为精准的格式,utf-8:全称Unicode Transformation Format,将数据量控制到最精简。
2、在读入内存时,需要将utf-8转成unicode。
所以我们需要明确:内存中用unicode是为了兼容万国软件,即便是硬盘中有各国编码编写的软件,unicode也有相对应的映射关系,但在现在的开发中,普遍在使用utf-8编码了,估计在将来的某一天等所有老的软件都淘汰掉了情况下,就可以变成:内存utf-8<->硬盘utf-8的形式了。
# 统一阶段
万国字符----------------内存:unicode=========utf-8==========>硬盘:utf-8二进制数
万国字符----------------内存:utf-8==========================>硬盘:utf-8二进制数
3.一般的乱码问题:
(1)存的时候出现乱码:
①原因:
采用的字符编码表无法识别输入的字符。
②解决方法:
存的时候已经乱码,无法补救,取得时候一定会乱。只有提前规避,在存入硬盘的编码格式用utf-8格式。
(2)存的时候没有乱码(采用的字符编码表可以识别输入的字符),但是取的时候乱码了:
①原因:
采用的字符编码表与当初存的时候用的不是同一张表。
②解决方法:
存的时候用什么编码,取的时候一代要用同样的编码格式。
4.如何解决与python程序有关的乱码问题:
(1)保证运行python程序的前两个阶段不乱码:
在python文件的开头加一行:
# coding:文件先前存硬盘的时候用的编码格式。
(2)保证第三个阶段不乱码:
使用python3,默认保存的是utf-8编码格式。
使用python2的时候,在字符串前面加小写的u作为前缀。
x = "上"
res1 = x.encode("gbk")
print(res1) # b'\xc9\xcf' 实际应是gbk编码格式二进制,python优化成16进制数据
res2 = x.encode("utf-8")
print(res2) # b'\xe4\xb8\x8a' 实际应是utf-8编码格式二进制,python优化成16进制数据
# python3中,自带优化机制,如果其他编码格式的二进制数转换成了Unicode格式的二进制,则自动转换成python3的str数据类型,如下所示:
res3 = res1.decode("gbk")
print(res3) # '上'
res4 = res2.decode("utf-8")
print(res4) # '上'
二、文件处理的基本操作
(一)什么是文件
文件是操作系统提供给用户/应用程序操作硬盘的一个虚拟单位。
(二)为何要用文件
为了在硬盘上存取数据,必须要使用到文件。
(三)如何使用文件
1.文件的基本使用
f = open(文件路径,打开模式) # 打开文件,向操作系统发送调用资源申请,并且在应用程序内使用文件句柄f关联文件内容。
f.write(数据) # 对文件进行读写操作
f.close() # 关闭文件,释放操作系统的资源
应用程序/用户 文件对象/文件句柄=================》遥控器
操作系统 打开文件a.txt============》空调
硬件 硬盘
2.文件的路径
在操作文件的时候,为了找到文件的地址,我们需要知道什么是文件的相对路径与绝对路径。
(1)绝对路径:
# windows系统
D:\python38\Doc\python383
C:\a\b\c\new.txt
# linux系统
/a/b/c/d.txt
file_path=r'C:\a\b\c\new.txt'
file_path=r'/a/b/c/d.txt'
# 转义符号r:
由于Windows系统中文件路径的分隔符是\,所以我们需要在路径前面加上r,变为原生字符串,防止转义符被读取。
(2)相对路径:
相对路径:相对于当前运行程序所在文件夹往后找,r"aaa/a.txt"
3.文件操作的示范:
# C:\Users\Bayer04\PycharmProjects\S15new\day10\a.txt
# '哈哈哈--hello'
1) 打开文本文件时,需要指定原文本文件在编写时使用的编码格式,用于在内存中解码,避免出现乱码。
# 当原编码格式的二进制文件从内存中加载到内存,并被正确的解码成Unicode格式的二进制后,python3解释器将这个数据直接转换成了字符串str类型的数据!
f = open(r"a.txt", mode="rt", encoding="utf-8")
res = f.read()
print(res,type(res)) # '哈哈哈--hello' <class 'str'>
f.close()
2) b模式打开文本文件出现错误! 一定不能指定encoding参数!!!
f = open(r"a.txt", mode="rb", encoding="utf-8")
res = f.read()
print(res) # ValueError: binary mode doesn't take an encoding argument
f.close()
3)正确的b模式打开文本文件的方式,先将**'bytes'字节**类型的二二进制数据存入内存中,python解释器帮我们优化成了16进制格式,以减少字节的长度。
f = open(r"a.txt", mode="rb")
res = f.read()
print(res,type(res)) # b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88--hello\r\n' <class 'bytes'>
x = res.decode('utf-8')
print(x) # 哈哈哈--hello
f.close()
4)使用b模式打开图片文件,将图片以字节的形式读入内存。
f = open('aaa.jpg', mode="rb")
res = f.read()
print(res) # b'\xff\xd8\xff\···'
f.close()
hon解释器帮我们优化成了16进制格式,以减少字节的长度。
f = open(r"a.txt", mode="rb")
res = f.read()
print(res,type(res)) # b'\xe5\x93\x88\xe5\x93\x88\xe5\x93\x88--hello\r\n' <class 'bytes'>
x = res.decode('utf-8')
print(x) # 哈哈哈--hello
f.close()
4)使用b模式打开图片文件,将图片以字节的形式读入内存。
f = open('aaa.jpg', mode="rb")
res = f.read()
print(res) # b'\xff\xd8\xff\···'
f.close()