一 字符编码
1 字符编码的定义:
计算机要想工作必须通电,即用‘电’驱使计算机干活,也就是说‘电’的特性决定了计算机的特性。电的特性即高低电平(人类从逻辑上将二进制数1对应高电平,二进制数0对应低电平),关于磁盘的磁特性也是同样的道理。结论:计算机只认识数字
很明显,我们平时在使用计算机时,用的都是人类能读懂的字符(用高级语言编程的结果也无非是在文件内写了一堆字符),如何能让计算机读懂人类的字符?
必须经过一个过程:
字符--------(翻译过程encoding)------->数字
这个过程实际就是一个字符如何对应一个特定数字的标准,这个标准称之为字符编码。
2 用户在使用应用程序时的一个过程:如下图所示当应用程序需要进行文件操作时,我们首先打开文件编辑器,然后向操作系统发出指令,需要读取硬盘中的文件,
这个时候操作系统会向cpu发出指令,cpu将文件读取到内存中,然后应用程序与内存之间进行存取操作。
3 文本编辑器存取文件与python解释器执行py文件的本质区别:
对于文本编辑器来说:
1)打开编辑器就打开了启动了一个进程,是在内存中的,所以,用编辑器编写的内容也都是存放与内存中的,断电后数据丢失,数据的存储是暂时性的
2)要想永久保存,需要点击保存按钮:编辑器把内存的数据刷到了硬盘上。
3)在我们编写一个py文件时,跟编写其他文件没有任何区别,编写的结果就是一堆字符。
对于python解释器来说:
第一阶段:python解释器启动,这一阶段与文本编辑器是一样的。
第二阶段:python解释器相当于文本编辑器,去打开test.py文件,从硬盘上将test.py的文件内容读入到内存中(小复习:pyhon的解释性,决定了解释器只关心文件内容,不关心文件后缀名)
第三阶段:python解释器开始解释执行,那么在这个过程中,python解释器会检测文件的语法。所以文本编辑器与python解释器的区别主要体现在第三阶段。
阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII
ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符
ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后来为了将拉丁文也编码进了ASCII表,将最高位也占用了
#阶段二:为了满足中文和英文,中国人定制了GBK
GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符
为了满足其他国家,各个国家纷纷定制了自己的编码
日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里
#阶段三:各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。如何解决这个问题呢???
#!!!!!!!!!!!!非常重要!!!!!!!!!!!!
说白了乱码问题的本质就是不统一,如果我们能统一全世界,规定全世界只能使用一种文字符号,然后统一使用一种编码,那么乱码问题将不复存在,
ps:就像当年秦始皇统一中国一样,书同文车同轨,所有的麻烦事全部解决
很明显,上述的假设是不可能成立的。很多地方或老的系统、应用软件仍会采用各种各样的编码,这是历史遗留问题。于是我们必须找出一种解决方案或者说编码方案,需要同时满足:
#1、能够兼容万国字符
#2、与全世界所有的字符编码都有映射关系,这样就可以转换成任意国家的字符编码
这就是unicode(定长), 统一用2Bytes代表一个字符, 虽然2**16-1=65535,但unicode却可以存放100w+个字符,因为unicode存放了与其他编码的映射关系,准确地说unicode并不是一种严格意义上的字符编码表,下载pdf来查看unicode的详情:
链接:https://pan.baidu.com/s/1dEV3RYp
很明显对于通篇都是英文的文本来说,unicode的式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)
于是产生了UTF-8(可变长,全称Unicode Transformation Format),对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存
#总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。
复制代码
View Code
基于目前的现状,内存中的编码固定就是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的形式了。
总结:
1 保证不乱码的核心法则就是,字符按照什么标准而编码的,就要按照什么标准解码,此处的标准指的就是字符编码。
2 在内存中写的所有字符,一视同仁,都是unicode编码,比如我们打开编辑器,输入一个“你”,我们并不能说“你”就是一个汉字,
此时它仅仅只是一个符号,该符号可能很多国家都在使用,根据我们使用的输入法不同这个字的样式可能也不太一样。只有在我们往硬盘保存或者基于网络传输时,
才能确定”你“到底是一个汉字,还是一个日本字,这就是unicode转换成其他编码格式的过程了。
三 文件操作
对于文件的操作我们今天学了:文件的读’rt‘,写’wt‘,追加’at‘。
我们要想对文件进行操作首先应该打开文件,那么打开文件一般是f=open(r'文件路径',‘文件模式mode=’,'文件编码encoding=‘)文件路径在打开文件的过程是必不可少的,那么如果我
们没有填写文件模式那么默认的为只读模式:’rt‘其中’r‘代表了读,而’t‘则代表了文本txt。如果文件编码没有写那么默认为在windows下位gbk,在linux下为utf-8,所以我们为了防止我
们在读取文件是出现乱码,我们应该制定文件编码方式。
我们在打开一个文件的时候其实文件是占用了计算机两部分的资源,操作系统+应用程序,所以当我们在一个文件操作完毕时我们应该将文件关闭,可以使用两种方法:
1、f.close() #用来回收操作系统级打开的文件,在操作完毕后。
2、del f #回收应用程序级的变量
那么即使这样我们也时常会忘记关闭文件,导致系统资源的占用,那么我们在对文件进行操作时可以以这种方式:
with open(’a,txt‘,’文件模式‘,’encoding=utf-8‘)as f:
那么这样在文件操作完毕后会自动关闭。
还有一点就是:f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,
在windows下是gbk,在linux下是utf-8。这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
那么下面我们讲一些文件操作的实例:
只读:’rt‘
with open(’a,txt‘,'r','encoding=utf-8')as f:
for line in f:
print(line,end='')
或者:
with open('a,txt','r','encoding=utf-8')as f:
for line in f.lines:
print(line)
那么对于这两种方法我们不能用第二种,因为第二种是先将文件存成列表的形式,然后再输出,这样对于较大的文件会撑暴系统的内存。
只写:’wt‘
with open('a,txt','w','encoding=utf-8',) as f:
f.write('fhef')
f.writelines(['22\n','33\n','444\n'])
其中\n所代表的是手动输入换行符
对于write写入的是字符串数字等,对于writelines则写入的是列表。
当原来a,txt本来有值的时候,那么进行只读操作,会将原来文件中的内容清除。
如果你所要写入的文件不存在那么就会创建一个新的文件来存储用户写入的内容
追加:’at‘
with open('acess.log','a','encoding='utf-8')
f.write(222\n,333\n,)
对于文件的追加功能,与write不同的是他不会改变文件中原有的内容,只是会在文件的结尾继续添加索要添加的内容.