字符串类型、文本文件的内容都是由字符组成。但凡涉及到字符的存取,必须要考虑字符编码的问题。
1、计算机三大核心部件的关系所有的软件都是运行在操作系统上的,而操作系统是运行在计算机硬件上的,与软件运行相关的三大核心硬件是:CPU、内存和硬盘。
1、软件运行前,软件中的代码及其相关的数据都存放于硬盘中。
2、软件启动时,先将数据从硬盘存入内存,然后 CPU 从内存中读取指令并执行。
3、软件运行过程中产生的数据都是先存放在内存中,若想永久保存数据,必须由内存写入硬盘。
2、 文本编辑器读取文件内容的流程三个阶段:
1、启动文本编辑器。
2、文本编辑器将文件内容从硬盘读入内存。
3、文本编辑器将内存中读入的内容显示到屏幕上。
3、python解释器执行文件的流程以python demo.py为例
三个阶段: 1、启动python解释器,相当于启动文本编辑器。 2、python解释器,从硬盘上将demo.py文件的内容读取到内存中。 3、python解释器解释执行读取到内存中的内容,开始识别python语法4、python解释器与文本编辑器的差异
相同:前两个阶段完全一致,都是将硬盘中文件的内容读取到内存中。
python解释器是解释执行文件内容,所以python解释器具备读py文件的功能,与文本编辑器一样。
区别:在第三阶段时,内存中读取的内容处理方式不同。
文本编辑器将文件内容读取到内存后,是为了显示或者编辑,不去理会python语法,就是为了让我们瞅一眼代码写的什么。
python解释器将文件内容读取到内存后,是为了执行python代码、识别python语法。
2、定义1、什么是字符编码
人与计算机进行交互时,用的都是人能读懂的字符,如:中文字符、英文字符
计算机是基于电工作的,电的特性就是高低电频,人类从逻辑层面将高电频对应为数字1,低点频对应为数字0。这就是**计算机只能识别二进制**的由来。 • 所以,人能识别的字符与计算机能识别的字符必须经过**翻译**。翻译的标准称为字符编码表,该表上存放的就是字符与数字的一一对应关系。字符编码中的**编码**就是翻译或**转换**的意思,即将人能理解的字符翻译为计算机能识别的数字。
目的:将人类的语言转换成计算机能识别的语言
3、字符编码发展史概述 三个阶段: 1、计算机起源于美国,所以最优先考虑是让计算机识别英文字符,于是诞生了ASCII表。ASCII表的特点: 1、只有英文字符与数字的一一对应关系 2、一个英文字符对应1Bytes,1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符 3、实际上7bit就足够表示所有的英文字符,用8bit的目的是方便以后英文有新的字符添加作准备。2、计算机迅速发展阶段
因为计算机只能识别英文字符,不方便其他国家用户的使用。所以在此基础上各个国家都制定了自己的字符编码表,只能识别自己国家的官方字符和英文字符。
如:中国的GBK,能够识别中文字符和英文字符
GBK表的特点: 1、只有中文字符、英文字符与数字的一一对应关系 2、一个英文字符对应1Bytes 一个中文字符对应2Bytes 补充: 1Bytes=8bit,8bit最多包含256个数字,可以对应256个字符,足够表示所有英文字符 2Bytes=16bit,16bit最多包含65536个数字,可以对应65536个字符,足够表示所有中文字符
文本文件内容全都为字符,无论存取都是涉及到字符编码问题
#1、存文本文件
国人通过文本编辑器输入的字符会被转化成GBK格式的二进制存放于内存中,如果需要永久保存,则直接将内存中的GBK格式的二进制写入硬盘
#2、读文本文件
直接将硬盘中的GBK格式的二进制读入内存,然后通过GBK表反解成英文字符
文件无论是存还是取由于采用的字符编码表一样,所以肯定不会出现乱码问题。但问题是在美国人用的计算机里只能输入英文字符,而在中国人用的计算机里只能输入中文字符和英文字符……。
我们希望计算机允许我们输入万国字符均可识别、不乱码,而现阶段计算机采用的字符编码ASCII、GBK都无法识别万国字符,所以必须定制一个兼容万国字符的编码表。
3、万国字符unicodeunicode于1990年开始研发,1994年正式公布。
1、兼容万国字符,与万国字符都有对应关系。
2、与传统的字符编码的二进制数都有对应关系
3、采用16位(16bit=2Bytes)二进制数对应一个中文字符串个别生僻会采用4Bytes、8Bytes
很多地方或老的系统、应用软件仍会采用各种各样传统的编码,这是历史遗留问题。软件是存放于硬盘的,而运行软件是要将软件加载到内存的,面对硬盘中存放的各种传统编码的软件,想让我们的计算机能够将它们全都正常运行而不出现乱码,内存中必须有一种兼容万国的编码,并且该编码需要与其他编码有相对应的映射/转换关系,这就是unicode的第二大特点产生的缘由。
4、老的字符编码都可以转换成unicode,但是不能通过unicode互转
文本编辑器输入任何字符都是最新存在于内存中,是unicode编码的,存放于硬盘中,则可以转换成任意其他编码,只要该编码可以支持相应的字符。
# 英文字符可以被ASCII识别 英文字符--->unciode格式的数字--->ASCII格式的数字(硬盘) # 中文字符、英文字符可以被GBK识别 中文字符、英文字符--->unicode格式的数字--->gbk格式的数字(硬盘)4、utf - 8 的由来
理论上是可以将内存中unicode格式的二进制直接存放于硬盘中。由于unicode固定使用两个字节来存储一个字符,如果多国字符中包含大量的英文字符时,使用unicode格式存放会额外占用一倍空间(英文字符其实只需要用一个字节存放即可),然而空间占用并不是最致命的问题,最致命地是当我们由内存写入硬盘时会额外耗费一倍的时间,所以将内存中的unicode二进制写入硬盘或者基于网络传输时必须将其转换成一种精简的格式,这种格式即utf-8(全称Unicode Transformation Format,即unicode的转换格式)
utf-8是针对Unicode的可变长度字符编码:一个英文字符占1Bytes,一个中文字符占3Bytes,生僻字用更多的Bytes存储。 unicode更像是一个过渡版本,我们新开发的软件或文件存入硬盘都采用utf-8格式,几十年以后,所有老编码的文件都淘汰掉之后,硬盘里放的都是utf-8格式,此时unicode便可以退出历史舞台,内存里也改用utf-8。4、字符编码的应用
在诸多文件类型中,只有文本文件的内存是由字符组成的,因而文本文件的存取也涉及到字符编码的问题。
如何解决乱码:
#1、内存中固定使用unicode无论输入任何字符都不会发生乱码 #2、我们能够修改的是存/取硬盘的编码方式,如果编码设置不正确将会出现乱码问题。乱码问题分为两种:存乱了,读乱了 #2.1 存乱了:如果用户输入的内容中包含中文和俄文字符,如果单纯以GBK存,中文可以正常写入硬盘,而由于俄文字符在GBK中没有找到对应关系而导致存乱了,以此会引起存入的俄文数据丢失。 #2.2 读乱了:如果硬盘中的数据是俄文格式存储的,采GBK格式读入内存就读乱了
分两个阶段:
#1. 保证存的时候不乱:在由内存写入硬盘时,必须将编码格式设置为支持所输入字符的编码格式 #2. 保证读的时候不乱:在由硬盘读入内存时,必须采用与写入硬盘时相同的编码格式python解释器解决乱码 1、python解释器执行文件的前两个阶段
在执行py文件的前两个阶段就是python解释器将文件从硬盘读入内存的过程,需要保证读不乱码。即将python解释器读文件时采用的编码方式设置为文件当初写入硬盘时的编码格式。如果没有设置,python解释器就会使用默认的编码和解码方式,在python3中默认为utf-8,在python2中默认为ASCII,可以通过指定文件头的方式来修改默认的编码。
文件头:文件的首行
# coding:写入硬盘时采用的编码格式
读取文件时python解释器会先用默认的编码方式读取文件的首行内容,由于首行是英文字符组成,任何编码方式都可以识别英文字符。
2、python解释器执行文件的第三个阶段经过前两个阶段后py文件的内容都会以unicode的格式存放于内存中。
在经历第三个阶段时开始识别python语法,当遇到特定的语法name = '上'(代码本身也都全都是unicode格式存的)时,需要申请内存空间来存储字符串'上',这就又涉及到应该以什么编码存储‘上’的问题了。
在Python3中,字符串类的值都是使用unicode格式来存储
由于Python2的盛行是早于unicode的,因此在Python2中是按照文件头指定的编码来存储字符串类型的值的(如果文件头中没有指定编码,那么解释器会按照它自己默认的编码方式来存储‘上’),所以,这就有可能导致乱码问题
# coding:utf-8
x = u'上' # 即便文件头为utf-8,x的值依然存成unicode
python2解释器有两种字符串类型:str、unicode
# str类型
x='存' # 字符串值会按照文件头指定的编码格式存入变量值的内存空间
# unicode类型
x=u'存' # 强制存成unicode
python2后来推出了一种补救措施,就是在字符串类型前加u,则会将字符串类型强制存储unicode,这就与python3保持一致了,对于unicode格式无论丢给任何终端进行打印,都可以直接对应字符不会出现乱码问题
5、字符串的编码和解码
# 1、编码:unicode格式------编码encode-------->其它编码格式
x='存' # 在python3在'上'被存成unicode
res=x.encode('utf-8')
print(res,type(res)) # unicode编码成了utf-8格式,而编码的结果为bytes类型,可以当作直接当作二进制去使用
b'xe5xadx98'
# 2、解码:其它编码格式------解码decode-------->unicode格式
res.decode('utf-8')
'存'
二、文件操作open()函数
1、什么是文件
文件就是操作系统提供给用户或应用程序来操作硬盘的虚拟概念。
2、为什么要有文件因为程序运行中所产生的数据都是先放在内存中的,而内存是基于电工作的,它不能永久保存数据(断电数据会丢失)。若是想将数据永久保存下来,必须保存到硬盘中。应用程序想要操作硬件又必须通过操作系统进行操作。所以必须通过对文件的操作,从而向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。而有了文件的概念,我们可以不用再考虑操作硬盘的细节,只需要关注操作文件的流程就好。
3、文件的基本操作对文件的操作,主要是:打开文件、操作文件(读、写文件)及关闭文件三方面的操作。
1、打开文件对于windows平台: '' '' 反斜杠在python中表示转意,所以不能直接复制文件路径打开文件。
open('D:textdemo.py') # 文件不会被读取
# 解决方法1 (推荐)
open(r'D:textdemo.py') # 用 r 让字符原样输出
# 解决方法2
open('D:/text/demo.py') # pycharm会自动识别
将函数open()赋值给一个变量
# 打开文件,由应用程序向操作系统发起系统调用open(...),操作系统打开该文件,对应一块硬盘空间,并返回一个文件对象(文件句柄)赋值给一个变量file file = open(r'D:textdemo.py',mode='rt') # r读操作 和 t文本模式 是open的默认值 file是一个变量,占用的是应用程序的内存空间 print(file) # file属于文件类型 y = int(7) # open()和int()的区别 ''' open先创造文件对象,占用的是操作系统内存,而赋值给变量file是占用应用程序的内存空间。(这个文件会对应操作系统打开的文件,所以它也占用操作系统空间,操作系统会将自己的文件映射到硬盘的具体空间上) int只占应用程序的内存空间 '''2、操作文件
应用程序对文件的读写请求都是在向操作系统发送系统调用,然后由操作系统控制硬盘把数据读取到内存或者从内存写入硬盘。
# 对file的任何请求就是对操作系统的内存空间写入命令 result = file.read() # 调用文件对象下的读/写方法,会被操作系统转换为对硬盘的读/写操作3、关闭文件
向操作系统发起关闭文件的请求,回收操作系统资源
file.close() # 向操作系统发起关闭文件的请求,回收操作系统资源 file.read() # 变量file存在,但是操作系统上的资源被回收了,所以读取失败 # del file # 回收变量,因为python有垃圾回收机制,所以程序中不用写此行代码4、with 上下文管理
格式:with open(...) as 赋值的变量名
应为操作系统能开启的文件数量是有限的,所以我们对文件进行操作后必须要关闭,但是我们可能会忘记关闭,操作系统虽然会自动帮我们关闭,这样会对操作系统增加不必要的负担。所以python的管理者引入了with语句,目的是当我们退出后会帮我们自动关闭操作完的文件。
with open('demo.txt', mode='rt') as file,
open('text.txt', mode='rt') as file2:
...
# 只要退出with语句它就会自动关闭文件
5、指定字符编码
文本的模式 t 和 b 不能 单独使用,必须跟 r、w、a 连用。
t 文本是默认的模式
1、读写都是以str(unicode)为单位的 2、必须是文本文件,不能是图片或者视频 3、必须指定encoding='utf-8'(推荐使用uft-8,也可以使用别的字符编码格式) 没有指定encoding参数操作系统会使用自己默认的编码: linux系统默认utf-8 windows系统默认gbk(所以windows系统不指定会报错)
with open('demo.txt', mode='rt', encoding='utf-8') as file:
result = file.read() # t模式会将file.read()读出的结果解码成unicode
# read()方法:在硬盘中的demo.txt文件是utf-8编码格式的二进制,从硬盘中读取到内存中的格式也是utf-8格式的二进制。但是由于t模式的限制,必须转码为str也就是unicode格式的编码。
6、文本文件的操作
指定的文本文件常用t模式,相较b模式更加简便。
1、r只读操作模式(默认的操作模式)
当文件不存在时会报错,当文件存在时文件指针跳到文件开始位置
# 2、编写登录程序,账号密码来自于文件demo.txt
# sun:123
# east:123
in_username = input('输入你的用户名:')
in_password = input('输入你的密码:')
with open('demo.txt', encoding='utf-8') as file:
# file.write('tom:123') # 报错
for i in file: # 从文件中一行一行的取出数据,避免文件过大造成内存溢出(为防止一行数据也过大的情况可以使用while循环进行限制)
# 因为文件中的数据都是以/n为分割符的,在数据中直接将其视为空格用strip()方法去除
username,password = i.strip().split(':')
if username == in_username and password == in_password:
print('输入正确!!!')
break # 文件比对准确了之后必须结束循环,不然会继续遍历比对
else: # 当所有比对结果都不对后进入
print('错误!!!')
2、w 只写操作模式
当文件不存在时,会创建空文件。当文件存在会清空文件中的数据,指针跳到文件开始位置
# 在w操作模式下,打开的文件没有关闭的情况下,连续写入,新的数据内容会跟在旧数据之后。
with open('demo.txt', encoding='utf-8') as file:
file.write('won')
file.write('wo!n')
file.write('wo!!n')
# 如果重新以w操作模式打开文件,会清空文件中的内容
with open('demo.txt', encoding='utf-8') as file:
file.write('won')
with open('demo.txt', encoding='utf-8') as file:
file.write('wo!n')
# 1、编写文件copy工具
with open('demo.txt',encoding='utf-8') as file2,
open('b','wt',encoding='utf-8') as file3:
result = file2.read()
file3.write(result)
3、a 只追加写操作模式
在文件不存在时会创建空文件。在文件存在时文件指针会直接跳到末尾。与w不同的是:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾,新写的内容永远写在最后。
with open('b', mode='at', encoding='utf-8') as f:
# f.read() 报错
f.write('hello worldn')
f.write('hello starn')
# w 模式与 a 模式
# 相同点:在打开的文件不关闭的情况下,连续写入内容,新的内容总是跟在前面内容的后面。
# 不同点:以 a 模式重新打开文件,不会清空原文件内容,文件的指针会移动到文件末尾,
# 新的内容一直在旧内容之后。
# a 模式通常用来记录日志、注册的用户信息保存
name = input('请输入你的名字:')
password = input('请输入你的密码:')
with open('b', mode='at', encoding='utf-8') as f:
f.write('{}:{}n'.format(name, password))
4、 + 模式:不能单独使用,必须与r、w、a 模式联用
# + 可以是:r+t、rt+等表示
# r 与 + 模式的联合使用使得能够往文件里面写入内容,由于r 模式的指针是在开头,再往里面写入内容就会覆盖原有的内容,通常是写入几个字符就覆盖几个。
with open('b',mode='rt+',encoding='utf-8') as f:
f.write('hi')
# w 与 + 模式的联合,使得能够使用read()方法读取文件中的内容,由于w 模式会清空文件中的原有数据,并且往里面写入的内容一直是在文件的末尾,所以read()读取不到任何内容。
with open('b',mode='w+t',encoding='utf-8') as f:
f.write('111n')
f.write('222n')
f.write('777n')
print('->>>>',f.read()) # 为了验证读方法能够使用,并不是没有输出而是因为指针在文件末尾,所以读取不了任何内容
# a 与 + 模式的联合,使得文件能够被读取,与 w + 模式类似,虽然a 模式不会清空文件中的数据,但是由于指针在文件末尾的原因。。。
with open('b',mode='a+t',encoding='utf-8') as f:
print(f.read())
f.write('2222n')
f.write('7777n')
print(f.read())
4、文件的高级操作
1、x 模式
x模式是控制文件操作的模式;只写模式(不可读),若文件存在会报错,文件不存在创建文件。
with open('x',mode='x',encoding='utf-8') as f:
# f.read() 报错
f.write('文件存在报错,文件不存在创建 a 文件')
2、b 模式
控制文件读写内容的模式 t 模式:
1、读写都是以字符串(unicode)为单位 2、只能针对文本文件 3、必须指定字符编码,即必须指定encoding参数
b 模式(binary):
1、读写都是以bytes为单位 2、可以针对所有文件 3、一定不能指定字符编码,即一定不能指定encoding参数
总结:
1、在操作纯文本文件时,t模式帮我们省去了编码与解码的环节,b模式则需要手动编码与解码。 2、针对非文本文件(如:图片、视频等)只能使用b模式
t模式只能读取文本文件,因为它读写都是以字符串(unicode)为单位,在对图片、视频等非文本文件操作时,t模式会将硬盘中读入内存的内容进行decode解码操作,所以会造成 “乱码”的情况,使得读取的内容出现错误。
对于b 模式而言,硬盘中的数据是二进制的形式,所以不会做任何转换,直接从硬盘读入内存中。
with open('b.txt',mode='wb') as f: # open()参数不能指定encoding
f.write('hello'.encode('utf-8')) # 对于纯文本文件必须进行编码
with open('b.jpg',mode='rb') as f:
f.read()
3、文件的拷贝工具
src_file = input('源文件路径:').strip() # 去除路径两端不小心输入的空格
dst_file = input('目标文件路径:').strip()
with open(r'{}'.format(src_file)) as f1,
open(r'{}'.format(dst_file)) as f2: # r用于路径的原有输出
result = f1.read()
f2.write(result)
# 上面应用的文件复制方法有一个隐患,就是文件的read()方法读取内容时,是将文件中的所有内容都读取到内存中,这样肯会造成内存占用过大。
# 解决1:可以通过读取一行内容写入一行内容
# for line in f1:
# f2.write(line)
# 解决2:虽然读取一行写入一行极大的节省了内存的损耗,但是文件中也可能出现一行内容数据量过大的情况,所以我们通过指定读取的字节数量来节省内存。
with open('text.png',mode='rb') as f:
while True:
result = f.read(1024) # 若用 b 模式是以字节为单位
if len(result) == 0:
break
4、文件中的操作方法
1、读相关的方法
# 1、readline:一次读一行
with open('R.txt', mode='rt', encoding='utf-8') as f:
# res1=f.readline()
# res2=f.readline() # 指针从第一行尾移动到第二行尾
# print(res2)
while True:
line = f.readline()
if len(line) == 0:
break
print(line)
# 2、readlines:一次读取多行
with open('b', mode='rt', encoding='utf-8') as f:
result = f.readlines()
print(result)
# f.read()与f.readlines()都是将内容一次性读入内存,如果内容过大会导致内存溢出,若还想将内容全读入内存,可以使用for循环一次读入一行数据或者while循环一次读入指定的数据长度读入内存中。
2、写相关的方法
# f.writelines():一次性写入多行数据
with open('text.txt',mode='wt',encoding='utf-8') as f:
# f.write('1111n222n3333n')
# l=['11111n','2222','3333',4444]
l=['11111n','2222','3333']
# for line in l:
# f.write(line)
f.writelines(l)
with open('b .txt', mode='wb') as f:
# l = [
# '1a1n'.encode('utf-8'),
# '2bb2'.encode('utf-8'),
# '3eee3'.encode('utf-8')
# ]
# 1:如果是纯英文字符,可以直接加前缀b得到bytes类型
# l = [
# b'1a1n',
# b'2bb2',
# b'3eee3'
# ]
# 2:'存'.encode('utf-8') 等同于bytes('存',encoding='utf-8')
l = [
bytes('存',encoding='utf-8'),
bytes('进',encoding='utf-8'),
bytes('去啦',encoding='utf-8'),
]
f.writelines(l)
3、快速存入硬盘的方法 flush()
# 新建的文件中写入内容时,计算机并不是实时将数据存入硬盘,而是积累到预设值后统一从内存存入硬盘中。flush()方法就可以实现计算机实时将数据存入硬盘中。
with open('f.txt', mode='wt', encoding='utf-8') as f:
f.write('实时存入硬盘')
f.flush()
4、补充
with open('text.txt', mode='wt', encoding='utf-8') as f:
print(f.readable()) # 该模式能否读文件
print(f.writable()) # 该模式能否写文件
print(f.encoding) # 该模式文件的字符编码
print(f.name) # 文件名
print(f.closed) # 是否关闭
5、控制文件指针的移动
指针移动的单位都是以bytes(字节)为单位的。 t 模式下的read(n),n代表的是字符个数。
with open('text.txt',mode='rt',encoding='utf-8') as f:
res=f.read(4)
print(res)
seek()方法
# f.seek(n,模式):n指的是移动的字节个数 # 模式0:参照物是文件开头位置 f.seek(7,0) f.seek(2,0) # 2 # 模式1:参照物是当前指针所在位置 f.seek(7,1) f.seek(2,1) # 9 # 模式2:参照物是文件末尾位置,应该倒着移动 f.seek(-7,2) # 2 f.seek(-2,2) # 7 # 强调:只有0模式可以在t下使用,1、2必须在b模式下用
tell()方法
# f.tell() # 获取文件指针当前位置
with open('text.txt', mode='rb') as f:
f.seek(7, 0)
f.seek(2, 0) # 2
# print(f.tell())
f.seek(4, 0)
result = f.read()
print(result.decode('utf-8'))
with open('text.txt', mode='rb') as f:
f.seek(7, 1)
f.seek(2, 1) # 9
print(f.tell())
with open('text.txt', mode='rb') as f:
f.seek(-7, 2)
# print(f.tell())
f.seek(-2, 2)
# print(f.tell())
print(f.read().decode('utf-8'))
# seek()方法动态追踪用户日志
with open('text.log',mode='rb') as f:
# 将指针跳转到文件末尾,用read()指针最终是在文件开头
f.seek(0,2)
while True:
line = f.readline()
if len(line) == 0:
continue
else:
print(line.decode('utf-8'))
修改文件的两种方式
# 方式一:文本编辑器采用的就是这种方式
# 实现思路:将文件内容一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件。
# 优点: 在文件修改过程中同一份数据只有一份
# 缺点: 会过多地占用内存
with open('c.txt', mode='rt', encoding='utf-8') as f:
result = f.read()
data = result.replace('原数据', '现数据')
print(data)
with open('c.txt', mode='wt', encoding='utf-8') as f1:
f1.write(data)
# 方式二:
import os
# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
# 优点: 不会占用过多的内存
# 缺点: 在文件修改过程中同一份数据存了两份
with open('c.txt', mode='rt', encoding='utf-8') as f,
open('.c.txt.swap', mode='wt', encoding='utf-8') as f1:
for line in f:
f1.write(line.replace('原数据', '现数据'))
os.remove('c.txt')
os.rename('.c.txt.swap', 'c.txt')
f = open('a.txt')
result = f.read()
print(result)
禁用笔记本键盘 sc config i8042prt start= disabled 启用笔记本键盘 sc config i8042prt start= auto



