字符编码与文件处理

发布时间 2023-05-23 21:12:36作者: Rachel1225

第一篇 字符编码

一、前提

字符串类型、文本文件的内容都是由字符组成的,但凡涉及到字符的存取,都需要考虑字符编码的问题。(跟视频文件、音频文件等无关)

 

二、字符编码介绍

2.1 为什么要有字符串编码?

人类在与计算机交互时,用的都是人类能读懂的字符但是计算机内部只认识01二进制数据。
#二进制数即由0和1组成的数字,例如010010101010。计算机是基于电工作的,电的特性即高低电平,人类从逻辑层面将高电平对应为数字1,低电平对应为数字0,这直接决定了计算机可以识别的是由0和1组成的数字
 
由人类的字符到计算机中的数字,必须经历一个过程,如下

 

翻译的过程必须参照一个特定的标准,该标准称之为字符编码表,该表上存放的就是字符与数字一一对应的关系

字符编码中的编码指的是翻译或者转换的意思,即将人能理解的字符翻译成计算机能识别的数字

 

2.2 字符编码表的发展史

2.2.1 阶段一:一家独大

现代计算机起源于美国,所以最先考虑仅仅是让计算机识别英文字符,于是诞生了ASCII表

# ASCII表的特点:
    1、只有英文字符与数字的一一对应关系
    2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符

需要你记忆的是:
A-Z:65-
a-z:97-
0-9:48-
# 字符串的比较:是按照ASCII码表的十进制数进行比较的  print('hello' > 'world') False

文本文件内容全都为字符,无论存取都是涉及到字符编码问题
#1、存文本文件
人类通过文本编辑器输入的字符会被转化成ASCII格式的二进制存放于内存中,如果需要永久保存,则直接将内存中的ASCII格式的二进制写入硬盘

#2、读文本文件
直接将硬盘中的ASCII格式的二进制读入内存,然后通过ASCII表反解成英文字符

 

 

2.2.2  群雄割据

中国人要想使用计算机,就自己开发了一套编码表:
GBK码表:它的内部记录了英文、中文和数字之间的对应关系

 
# GBK表的特点:
    1、只有中文字符、英文字符与数字的一一对应关系
    2、一个英文字符对应1Bytes
       一个中文字符对应2Bytes    
       补充说明:
       1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符
       2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符

日本人要想使用计算机,也得发明一套属于自己的编码表
Shift_JIS表
韩国人也要有一套属于自己的编码表
Euc-kr表

 

2.2.3. 一统天下

为了让世界上的所有国家之间能够彼此无障碍的交流,统一使用了编码unicode(万国码)

unicode于1990年开始研发,1994年正式公布,具备两大特点
#1. 存在所有语言中的所有字符与数字的一一对应关系,即兼容万国字符

#2. 与传统的字符编码的二进制数都有对应关系,详解如下

# 它的内部是统一使用两个字节保存字符或者更多字符
由于原来的英文字符是使用一个字节保存的,现在万国码使用了两个字节,所以就把资源浪费了一倍

 

文本编辑器输入任何字符都是最新存在于内存中,是unicode编码的,存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符

# 英文字符可以被ASCII识别
英文字符--->unciode格式的数字--->ASCII格式的数字

# 中文字符、英文字符可以被GBK识别
中文字符、英文字符--->unicode格式的数字--->gbk格式的数字

# 日文字符、英文字符可以被shift-JIS识别
日文字符、英文字符--->unicode格式的数字--->shift-JIS格式的数字

 

2.2.4utf-8的由来

理论上是可以将内存中unicode格式的二进制直接存放于硬盘中的,但由于unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式即utf-8(全称Unicode Transformation Format,即unicode的转换格式)

为何在内存中不直接使用utf-8呢?
utf-8是针对Unicode的可变长度字符编码:一个英文字符占1Bytes,一个中文字符占3Bytes,生僻字用更多的Bytes存储

unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,等过去几十年,所有老编码的文件都淘汰掉之后,会出现一个令人开心的场景,即硬盘里放的都是utf-8格式,此时unicode便可以退出历史舞台,内存里也改用utf-8,天下重新归于统一

 

2.3字符编码实操

2.3.1 如何解决字符乱码问题?

写的时候使用的是什么编码,打开的时候就使用什么编码打开

 

2.3.2  python解释器代码的差异

由于Python2的盛行是早于unicode的,因此在Python2中是按照文件头指定的编码来存储字符串类型的值的(如果文件头中没有指定编码,那么解释器会按照它自己默认的编码方式来存储‘上’),所以,这就有可能导致乱码问题

在python2 中,默认使用的是编码ASCII码

python3中默认使用的是utf8编码

# coding:utf-8
x = '' # x的值为untf-8格式的二进制
print(x) # 打印操作是将x的值,即utf-8格式的二进制交给终端,当终端收到后发现并不是unicode(只有unicode才与字符有对应关系),所以终端会执行操作:utf-8二进制---解码-->unicode格式的二进制,解码的过程终端会采用自己默认的编码,而在pycharm的终端默认编码为utf-8、windows下的cmd终端的默认编码为gbk,所以该打印操作在pycharm中显示正常,而在windows下的cmd中则乱码

# 在windows下的cmd中运行效果如下
C:\Users\Administrator>python2 E:\aaa.py
涓
 
python2后推出了一种补救措施,就是在字符串类型前加u,则会将字符串类型强制存储unicode
# coding:utf-8  解释器会先用默认的编码方式读取文件的首行内容
# 在python2中,默认使用的编码是ASCII码
    s = u'你好'  需要加'u"
    print s

 

2.3.3 编码和解码

编码

由字符转换成内存中的unicode,以及由unicode转换成其他编码的过程,都称为编码encode(是把其他字符串转为二进制的过程)

      str----->0101
      str----->unicode----->0101001
      ASCII---->GBK------>unicode----->utf8

 s = 'hello你好哈'
res = s.encode('utf8')
# print(res) # b'hello'  # 二进制 binary  bin()
print(res) # b'hello\xe4\xbd\xa0\xe5\xa5\xbd\xe5\x93\x88'

s1 =b'hello123' # 只能是纯英文字符
s2='hello123'.encode('utf8')

 

解码

由内存中的unicode转换成字符,以及由其他编码转换成unicode的过程,都称为解码decode

res1 = res.decode('utf8')  # gbk、utf8
print(res1)  # hello你好哈

 

 

第二篇 文件处理

一 、引入

当文件数量比较多的时候,人工操作就不太方便了,所以我们借助代码来操作

 

二、 文件操作的基本流程

2.1 基本流程

操作文件的流程:

三步骤:
1、 打开文件
2、操作文件(读、写)
3、关闭文件(释放资源的)

# 1. 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象赋值给一个变量f
f=open('a.txt','r',encoding='utf-8') #默认打开模式就为r

# 2. 调用文件对象下的读/写方法,会被操作系统转换为读/写硬盘的操作
data=f.read()

# 3. 向操作系统发起关闭文件的请求,回收系统资源
f.close()

 

2.2 资源回收与with上下文管理

打开一个文件包含两部分资源:应用程序的变量f和操作系统打开的文件。在操作完毕一个文件时,必须把与该文件的这两部分资源全部回收,回收方法为:

1、f.close() #回收操作系统打开的文件资源
2、del f #回收应用程序级的变量

其中del f一定要发生在f.close()之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源,
而python自动的垃圾回收机制决定了我们无需考虑del f,这就要求我们,在操作完毕文件后,一定要记住f.close(),虽然我们如此强调,但是大多数读者还是会不由自主地忘记f.close(),考虑到这一点,python提供了with关键字来帮我们管理上下文

# 1、在执行完子代码块后,with 会自动执行f.close()
with open('a.txt','w') as f:
    pass 

# 2、可用用with同时打开多个文件,用逗号分隔开即可
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:  
    data = read_f.read()
    write_f.write(data)