一、字符编码
# 文件用什么编码存,就用什么编码取
# 字符--->unicode--->utf-8/ASCII/gbk 正向为编码,反向为解码
# 用户输入 内存 存入硬盘(bytes类型)
# 往硬盘里存的数据和在网络上传输的数据都为bytes类型,一个中文字符为3bytes,一个英文字符1bytes,可以看作是二进制
1、文本文件内存中都是unicode编码
# python解释器会帮你把Unicode转成了对应的字符
# utf-8:就是Unicode的转换,在硬盘上存储
2、python解释器默认读文件的编码
# python3:utf-8
# python2:ASCII
# 如果pyhton3的文件运行在python2中要在文件头加 #coding:utf-8 使之可以读出python3存的数据
# 如果pyhton2的文件运行在python3中要在文件头加 #coding:ASCII 并且要在字符串前加u 即x = u'撒谎快递回来看见'
3、指定文件头默认的编码,在python首行写,下面的代码不是注释
#coding:gbk
# 只能控制的读文件,为当初存入硬盘时的编码
4、python3的str类型默认直接存成Unicode编码
# 如果是python2的话应该在字符串前面加个u,代表强制存为Unicode
x = u'撒谎快递回来看见'
print(x)
5、encode:编码 decode:解码 默认都为utf-8
x = '上'
print(x)
res = x.encode('gbk') # 把内存的Unicode编码为gbk,为bytes二进制类型
print(res) # \X 为十六进制的Unicode编码
g = res.decode('gbk') # 把硬盘的gbk解码成Unicode
print(g) # python解释器帮你把内存的Unicode转成了对应的字符
二、文件控制
1、主要函数open()的模式
# 控制文件读写内容的模式,t和b不能单独使用,必须r、w、a连用
# t (文本文件):
# 只能操作文本文件
# 读写都是以str(内存中为Unicode)为单位,可以把硬盘的二进制转为内存的Unicode
# 必须指定encoding的参数
# b (二进制/bytes):
# 可以操作任何类型的文件,
# 读出的都是bytes类型(可以当作是二进制)
# 一定不能指定encoding参数
# 控制文件读写操作的模式
# r(默认的):只读
# w:只写,只能写入字符串,或者bytes类型编码
# a:只追加写
2、open()打开文件,路径斜杠转义,前面加个r
# 注意:只打开文件不占用内存,只有对文件进行操作才会占用内存
x1 = open(r'C:\Users\admin\Desktop\基础命令与搭建\python\admin\xx.txt')
x2 = open(r'xx.txt') # 相对路径
print(x2) # x1的值是一种变量,占用的是应用程序的内存空间
3、操作文件
f = open(r'xx.txt', mode='rt', encoding='utf-8') #r、t代表读、文本
# read():读文件
res = f.read()
print(res)
4、close():关闭文件(一般使用with方法,不常用这个)
f.close() # 把f文件关闭,回收操作系统资源
# print(f.read()) # f关闭了以后,不可以再读了
三、with上下文管理器
# 文件对象又称文件手柄
# with可以最后自动关闭文件
'''
with open('xx.txt',mode='rt', encoding='utf-8') as f1: #f1=open('xx.txt',mode='rt')
res1=f1.read()
print(res1) #最后with已经自动关闭文本了
'''
# with可以打开多个文件
with open('xx.txt', mode='rt', encoding='utf-8') as f1, \
open('xxx.txt', mode='rt', encoding='utf-8') as f2: # \为换行转义实际还是一行
res2 = f2.read()
res1 = f1.read()
print(res1)
print(res2) # 最后with已经自动关闭文本了
四、指定文件编码
1、控制文件读写内容的模式,t和b不能单独使用,必须r、w、a连用
# 控制文件读写内容的模式,t和b不能单独使用,必须r、w、a连用
# t (文本文件):读写都是以str(内存中为Unicode)为单位,必须指定encoding='utf-8'
# b (二进制/bytes):
# 控制文件读写操作的模式
# r(默认的):只读
# w:只写
# a:只追加写
2、如果不指定encoding参数,操作系统会使用自己默认的编码解码,所以会乱码
# Linux系统默认utf-8
# Windows默认gbk
with open('xx.txt', mode='rt', encoding='utf-8') as f1:
res1 = f1.read() # t模式会将f.read()读出的结果解码为Unicode
print(res1, type(res1))
# 硬盘(xx.txt内容,为utf-8格式的二进制)
# 内存:uft-8格式的二进制---解码--->Unicode
# f1.write('哈哈哈') # 通过encoding参数指定的编码存入硬盘
五、文件操作模式详解
1、t (文本文件):
# 只能操作文本文件
# 读写都是以str(内存中为Unicode)为单位,可以把硬盘的二进制转为内存的Unicode
# 必须指定encoding的参数
1.1、r(默认的操作模式):只读模式,文件不存在会报错,只能读不能写,指针在文件开始位置
# read和readlines读的内容过大,可能会内存爆炸
# 可以使用for或者while循环读,循环是只取一行代码放入内存,显示或修改过后会回到硬盘
with open(r'a.txt', mode='rt', encoding='utf-8') as f:
print('第一次读'.center(50, '*'))
res = f.read() # 把所有二进制内容从硬盘读入内存为Unicode编码,
res1 = f.read(3) # 把前三个字符内容从硬盘读入内存为Unicode编码,
print(res) # txt文本每行后面都有\n作为换行,只是被read()进行了处理
print(res1)
with open(r'xx.txt', mode='rt', encoding='utf-8') as f:
print('第二次读'.center(50, '*'))
res1 = f.read() # 第二次读不出来是因为指针已经到最后了,需要重新打开文件再读
print(res1)
# r模式案例,利用for循环读
# txt文本每行后面都有\n作为换行,只是被read()进行了处理
# 如果使用for循环或者whil循环读取就会发现有/n存在,会影响匹配
with open(r'user.txt', mode='rt', encoding='utf-8') as f:
for i in f:
user_id, user_pwd = i.split(':') # 根据:切分
print(user_id, user_pwd)
# 去除\n版本
count = 0
x=1 #条件为真
while count<3 and x:
name = input("请输入id:")
pwd = input("请输入密码:")
with open(r'user.txt', mode='rt', encoding='utf-8') as f:
for i in f:
# txt文本的每一行最后都是带有隐藏的\n,来换行的
# print(i) # 存的时候为admin:123,所以输出格式为admin:123
user_id, user_pwd = i.strip('\n').split(':') # 去除两侧的\n,根据:切分
# print(user_id, user_pwd)
if name == user_id and pwd == user_pwd:
print("登入成功")
x = 0 #条件为假
break
else: # 要读完文本才可以判断输入的id和pwd是否在文本里,所以要和for循环同级
print("no")
count+=1
else:
print("错误次数过多")
1.2、w模式(重新打开文件,数据就清空);只写模式,文件不存在会创建空文件,当文件存在时会清空文件,指针在开始位置
with open('x.txt', mode='wt', encoding='utf-8') as f:
# f.read() #因为是只写,所以不能读
f.write('啊啊啊啊\n') # 把之前的删除,写入新的内容
f.write('呀呀呀') # 当文件没关闭的情况下,新写的内容在后写的内容之后
# w模式案例 用来创建新的文件,copy文件工具
x1 = input('请输入需要copy文件路径:').strip()
x2 = input('请输入新文件路径:').strip()
with open(r'{}'.format(x1), mode='rt', encoding='utf-8') as f1,\
open(r'{}'.format(x2), mode='wt', encoding='utf-8') as f2:
# with open(x1, mode='rt', encoding='utf-8') as f1,\
# open(x2, mode='wt', encoding='utf-8') as f2:
for i in f1:
f2.write(i) # 将f1的内容写入f2
1.3、a模式(在文档末尾追加):只追加写,文件不存在时会创建空文档,文件存在时,指针会跳到末尾
with open('xx.txt',mode='at',encoding='utf-8') as f:
f.write('啊啊啊\n')
f.write('1111')
# a模式案例 注册功能
name = input('name:')
pwd = input('pwd:')
with open('db.txt', mode='at', encoding='utf-8') as f:
f.write('{Name}:{Pwd}\n'.format(Name=name, Pwd=pwd))
x模式(不常用):只写模式,如果文件存在则报错,文件不存在就创建新文件
2、b (二进制/bytes):
# 可以操作任何类型的文件,
# 读写都是bytes类型(可以当作是二进制)
# 一定不能指定encoding参数
# 写入就要把写的内容都进行编码为bytes类型写入
2.1、r模式
with open(r'a.txt', mode='rb') as f:
res = f.read() # 读出中文的utf-8二进制
res = res.decode('utf-8') # decode把utf-8解码为Unicode
print(res)
2.2、w模式,如果使用b模式的话,写的字符串要进一步编码为二进制才可以写进去
with open(r'xxx.txt', mode='wb') as f:
f.write('admin'.encode('utf-8')) # encode把要写入的内容先编码后写入
# w模式案例,copy工具
# 在copy的时候,读出的为二进制,写入的也是二进制所以不需要编码解码
x1 = input('请输入需要copy文件路径:').strip()
x2 = input('请输入新文件路径:').strip()
with open(r'{}'.format(x1), mode='rb') as f1, \
open(r'{}'.format(x2), mode='wb') as f2:
for i in f1:
f2.write(i)
# 当文件过大数据过多的时候最好使用while循环
x1 = input('请输入需要copy文件路径:').strip()
x2 = input('请输入新文件路径:').strip()
with open(r'{}'.format(x1), mode='rb') as f1, \
open(r'{}'.format(x2), mode='wb') as f2:
while True:
res = f1.read(1024) # 读出f1 1024大小的内容进行解码并赋值给res
if len(res) == 0: # 因为读的过程中指针一直往后走,走到最后res的长度也就为0了
break
f2.write(res)
2.3、a模式同理
3、文件操作其他方法
3.1、readline:一次读一行
with open(r'a.txt', mode='rb') as f:
res = f.readline() # 读出中文的utf-8二进制
res = res.decode('utf-8') # decode把utf-8解码为Unicode
print(res)
3.2、readlines:一次读多行为集合形式,如果读的文件内容过大内存会爆内存
with open(r'a.txt', mode='rt',encoding='utf-8') as f:
res = f.readlines() # 相当于调用for循环读出内容,有\n存在
print(res)
with open(r'a.txt', mode='rb') as f:
res = f.readlines() # 相当于调用for循环读出内容,有\n存在
print(res)
3.3、writelines:将一个列表取出一次写入,等同与for循环取值
# t模式写入
with open(r'a.txt', mode='wt', encoding='utf-8') as f:
l = ['1111\n', '2222', '333']
res = f.writelines(l) # 相当于调用for循环,将l列表的值取出一次写入a.txt
print(res) # 因为只有一个\n,所以会取两次1111、2222333
# b模式写入
with open(r'a.txt', mode='wb') as f:
l = ['1111\n'.encode('utf-8'),
'2222'.encode('utf-8'),
'333'.encode('utf-8')]
res = f.writelines(l) # 相当于调用for循环,将l列表的值取出一次写入a.txt
print(res) # 因为只有一个\n,所以会取两次1111、2222333
3.4、closed、readable、writable
with open(r'a.txt', mode='wt', encoding='utf-8') as f:
print(f.readable()) # 判断代码是否可读
print(f.writable()) # 判断代码是否可写
print(f.closed) # 判断代码是否关闭
print(f.closed)
六、文件操作控制指针移动(不常用)
1、指针移动的单位都是以bytes/字节为单位
# 只有在t模式下的read(n),n代表的是字节个数
import time
#t模式的r模式n代表字符
with open('a.txt', mode='rt', encoding='utf-8') as f:
res = f.read(4) # 把文件的前4个字节读出
print(res)
# b模式为字节
with open('a.txt', mode='rb') as f:
res = f.read(4) # 把文件的前4个字节读出
#res = f.read(100).decode() # 把文件的前100个字节读出
print(res)
# tell() #获取文件指针位置
2、seek(n,模式):n指的是移动的字节个数,有模式1、2、3
# 模式:0、1、2,只有0模式可以在t模式和b模式下使用,1、2只能在b模式下用
# 模式0:参照物是文件开头位置为指针位置
with open('a.txt', mode='rb') as f:
f.seek(3, 0) # 将指针从开始移到第3个字节位置
f.seek(3, 0) # 将指针重新从0开始移到第3个字节位置
res = f.read().decode() # 读的时候从第3个字节后面开始读
print(res)
# 模式1:参照物是当前位置为指针位置
with open('a.txt', mode='rb') as f:
f.seek(3, 1) # 将指针移到第3个字节位置
f.seek(3, 1) # 将指针从第3个字节位置,再往后移动3个字节
res = f.read() # 读的时候从第3个字节后面开始读
print(res)
# 模式2:参照物是文件末尾位置为指针位置,应该到这移动
with open('a.txt', mode='rb') as f:
f.seek(-11, 2) # 将指针从文件末尾往文件开始位置移动11个字节
res = f.read() # 读的时候从指针位置后面开始读
print(res)
2.1、seek案例,编写一个监控access.log文件,显示最新添加的内容
import time
with open('access.log',mode='rb') as f:
f.seek(0,2) # 指针移动到末尾
while True:
line=f.readline() #每次读一行
if len(line)==0:
time.sleep(0.3)
else:
print(line)
七、文件操作之文件修改
1、流程
# 流程:硬盘数据读入内存--->修改内存数据--->覆盖写入硬盘
# 硬盘的数据没有修改一说,都是内存上新的数据覆盖了硬盘上的旧的数据
# 但是内存可以改,文件的修改就是把硬盘的所有数据读入内存,改完的内存覆盖回硬盘
# 注意:同时对一个文件读和操作时不可以连着写
# 用rt模式打开-->用wt模式打开,还没开始读操作,wt模式打开文件会清空原有的数据
with open('xx.txt', mode='rt', encoding='utf-8') as f1, \
open('xx.txt', mode='wt', encoding='utf-8') as f2:
res = f1.read()
2、方式一:省下了硬盘空间,耗费了内存空间
with open('w.txt',mode='rt',encoding='utf-8') as f1:
res=f1.read()
data=res.replace('张一蛋','张一蛋6') #replace方法把字符串中的旧字符串换成新字符串
print(data)
with open('w.txt',mode='wt',encoding='utf-8') as f2:
f2.write(data)
3、方式二:省下了内存空间,耗费了硬盘空间,修改速度快
import os # 导入os包
with open('xx.txt', mode='rt', encoding='utf-8') as f1, \
open('xx.txt.a', mode='wt', encoding='utf-8') as f2:
for i in f1: # for循环取值,内存中只有一行数据
f2.write(i.replace('123', 'admin')) # 将内存数据写入文件f2
os.remove('xx.txt') # 将原文件删除
os.rename('xx.txt.a', 'xx.txt') # 将新文件重命名为原文件