字符编码
因为计算机的工作原理就是靠电,而电的特性就是高低电平(0,1),所以说计算机只能读懂类似于一串010110101011001...这样的数字,而人类的语言却是很复杂的,对于计算机来说根本理解不了,这就需要某一种方式来转换,能够让两者之间进行交互,所以产生了字符编码。
定义:将字符一一对应到特定数字的标准。
- 字符编码的发展史
最早的字符编码是ASCII,只规定了英文字母、数字和一些特殊符号与数字的对应关系。最开始只用8位来表示一个字节,即2**8=256,所以它最多只能表示256个字符,随后相继出现了gbk,shift_jis,Euc_kr等各个国家的编码,后来又出现了Unicode,能够兼容各国的编码。
- 关于乱码的问题
由于世界上各个国家的编码方式都不一样,所以想要在全球范围使用同一个计算机是不可能的(各个国家的计算机内存和硬盘中用的是自己国家的字符编码),对于本国来说,如:中国的gbk编码,能够识别中文和英文,但是它识别不了泰语、韩语、日语等等,同样,日本的Shift_JIS也只能识别英文、日文,识别不了中文。所以说每个国家的编码只能在本国使用,再本国使用就不会有什么乱不乱码的问题了。
但是,要想通用计算机,那就有问题了。首先,各个国家的编码互不兼容,所以根本没法通用。那第二个问题(乱码问题),说白了乱码就是编码不统一造成的,那怎么统一呢?(目前来看,让全球统各国用同一种编码是不可能了),所以目前要解决的问题是:怎么能有一种既能兼容各国编码,又能与各国的字符编码都有映射关系,那这样就可以与其他的编码任意转换了,这就是Unicode(定长万国码),但是Unicode自身也存在一个问题,统一用2Bytes标识一个字符,这对存储一篇英文写的文本来说就是浪费空间,其次,如果文件过大,将会增加计算机的I/O次数,影响计算机的执行效率,所以随后又产生了UTF-8(可变长,全称Unicode Transformation Format)来解决这个问题。
总结:内存中统一采用Unicode,虽然浪费空间,但是可以转换成任意编码,能保证不乱码,硬盘则采用各种编码,保证存放于硬盘的数据量很小,能提高传输效率与稳定性。
所以:保证不乱码的前提就是,用哪种字符编码编码的,那就应该用同样的字符编码去解码!!!
文件处理
- 文件操作
文件的概念来源于操作系统,是操作系统提供的一种虚拟的储存数据的单位。所以我们只要关注操作文件的流程就OK!
# 1、打开一个文件,得到一个文件句柄并赋值给一个变量 f=open('s.txt','r',encoding='utf-8') # 2、通过句柄对文件进行操作 data=f.read() # 3、操作完关闭文件 f.close()
分析:应用程序向操作系统发起调用指令open(),然后操作系统打开一个文件,并返回这个文件句柄给应用程序,再由应用程序将文件句柄赋值给变量f。
- 打开一个文件包含两部分资源
1、操作系统级打开的文件(回收时f.close())
2、应用程序级的变量(回收时 del f)
注意点:操作系统打开文件时如果我们不指定字符编码,那操作系统就会默认为它自己的编码去打开文件(Windows是gbk,Linux是UTF-8),有时会造成乱码的现象,所以,就要用编码(encode)时的字符编码去打开(解码decode)该文件。f=open('s.txt','r',encoding='utf-8')
- 打开文件的模式
1、文本模式(默认)
文本打开的方式
r---只读模式(默认模式,文件必须要存在才能打开,否则会报错)
w---只写模式(不可读,文件不存在时会自动创建,有则清空内容)
a---追加写模式(不可读,文件不存在时会自动创建,存在则只在文件最末尾追加内容)
2、非文本模式(Bytes)
非文本模式打开方式
rb
wb
ab
非文本文件读取到的内容是字节类型(Bytes),写入时也要提供字节类型,不能指定字符编码
- 操作文件的方法
# 读 f.read() # 读取文件所有内容,同时光标移动到文件末尾 f.readline() # 读一行内容,光标移动到第二行开头位置 f.readlines() # 读取文件每一行内容,存放于一个列表中 # 写 f.write() # 针对文本模式,要自己写上换行符;对b模式,除了要写换行符,还要对写的内容编码.encode() f.writelines(['aaa\n','bbb\n']) # 文件模式 f.writelines([bytes('aaa\n',encoding='utf-8'),'bbb\n'.encode('utf-8')]) # b 模式
光标在文件内的移动
f.seek(offset,whence)
offset:偏移量(光标移动的字节数)
whence:参照物(0,1,2)
0、代表默认参照文件开头,通用于t与b模式
1、代表参照光标所在的当前位置,只能用于b模式
2、代表参照文件的末尾,只能用于b模式
# t模式下光标的移动 with open('a.txt', 'rt', encoding='utf-8') as f: msg = f.read(1) # 读到的是一个字符----你 print(msg) f.seek(6, 0) # 将光标从文件头移动6个字节 msg1 = f.read(1) # 读到的是一个字符----啊 print(msg1) # b模式下的光标移动 with open('a.txt', 'rb') as f: msg = f.read(3) # 从头开始读3个字节----你 print(msg.decode('utf-8')) f.seek(6, 1) # 从当前读到的位置开始光标移动6个字节 msg1 = f.read(4) # 再读出4个字节----hell print(msg1.decode('utf-8')) # b模式下的光标移动之倒移 f.seek(0, 2) # 会直接将光标移动到文件末尾 with open('a.txt', 'rb') as f: f.seek(-5, 2) # 文件内光标从末尾往前移动5个字节 msg1 = f.read(5) # 读取5个字节----hello print(msg1.decode('utf-8'))
注意:文件内指针的移动,只有在t模式下的read(n),n才表示的是字符的个数,除此之外,其余的都表示的是字节(Bytes)!!
修改文件的两种方式
# d.txt内容 ''' Jack说他很帅 Jack说他很浪 呵呵笑了笑Jack '''
with open('d.txt', 'rt', encoding='utf-8') as f: msg = f.read() with open('d.txt', 'wt', encoding='utf-8') as f: f.write(msg.replace('Jack', '帅逼'))
import os with open('d.txt', 'rt', encoding='utf-8') as read_f, \ open('d.txt.x', 'wt', encoding='utf-8') as wirte_f: for info in read_f: wirte_f.write(info.replace('帅逼', 'Jack')) os.remove('d.txt') os.rename('d.txt.x', 'd.txt')
总结: 优点 方式一:同一时间内硬盘中只有一份数据存在 方式二:对内存的占用很少 缺点 方式一:文件过大时会占用太多内存,降低运行效率 方式二:同一时间硬盘中会有两份数据存在