第8天文件操作
1. 文件操作
文件就是计算机的操作系统虚拟给用户操作硬盘的一个接口。我们都知道,内存和硬盘都是存储数据的,但是内存的数据易丢失,当我们需要在下次启动计算机的时候还能够看到我们写的东西,就必须要把我们的东西写入到硬盘中,这也就是文件存在的意义。
操作文件的三个步骤 1. 打开文件得到一个文件句柄
2. 通过这个文件句柄来对文件进行我们想要的操作
3. 向操作系统发送关闭指令,回收操作系统资源
2. 打开文件的模式
打开文件的模式总共有五种,三种纯净模式,r, w, a, 以及控制打开文件格式的两种模式: t, b
''' 控制文件格式的两种模式必须和三种纯净模式一块进行使用,不能单独使用: 三种纯净模式: r: 只读,文件指针在默认在开头,文件不存在就跑出异常 w: 只写,文件指针也在开头,文件不存在就创建,存在就清空内容写入 a: 追加写入,文件指针在结尾,文件不存在就创建,存在就追加写入 控制文件格式的两种模式: t:文本格式:只能操作文本文件,在这样的格式下一般需要指定处理文本的编码方式,否则无法跨平台进行使用
b: 二进制格式: 可以操作所有的文件,因此存储就是用的字节,所以在此模式下不能指定编码方式
'''
(1). r只读模式:在文件不存在的时候报错,文件存在指针直接跳到开头
简单的打开文件的方式:但是不建议这样写,因为如果没有指定mode和编码方式,采取的都是默认的,mode为rt,编码方式为操作系统默认的编码,如果一旦出现了跨平台的操作,就会出现乱码的问题!
with open('user_gbk') as f: print(f.readline(11))
# 无论打开什么文件,都建议指定模式和编码方式
with open('user_gbk', mode='rt', encoding='gbk') as f:
print(f.read())
文件读取的两种模式之 【rt】模式
# 以rt模式打开的建议指定上字符编码,单位为字符
with open('user_utf-8', 'rt', encoding='utf-8') as f:
# 把一个文件全部的内容读取出来,返回一个字符串,一般不建议这样读文件,容易撑爆内存 # data = f.read() # print(data, type(data), len(data)) # 读取当前指针所在行的值,传递的参数代表的是读取几个字符 data = f.readline(4) print(data) # 把每一行的值转换成一个字符串,最后返回一个列表 data = f.readlines() print(data)
文件读取的两种模式之 【rb】模式
# 以rb模式打开的不能指定字符编码,单位都是字节 with open('user_utf-8', 'rb') as f: # for line in f: # print(len(line)) # 把一个文件全部的内容读取出来,返回一个bytes类型,一般不建议这样读文件,容易撑爆内存 # 如果我们想查看内容,就用写入文件编码方式解码 # data = f.read() # print(data, type(data), len(data), data.decode('utf-8')) # 读取当前指针所在行的值,传递的参数代表的是读取几个字节 data = f.readline(3) print(data) # 把每一行的值转换成bytes类型,最后返回一个列表 data = f.readlines() print(data)
例题:以rb的形式读取一张图片
with open('ceshi.png', 'rb') as f: data = f.read() print(data)
(2)r只写模式:在文件不存在的时候创建,文件存在指针直接跳到开头,覆盖写入文件
文件写入的两种模式之 【wt】模式
# wt的模式写入的必须是字符串 with open('user_utf-8', 'wt', encoding='utf-8') as f: f.write('中国你好!'.encode('utf-8')) line = ['111', '222', '444'] # 下面这两种方法是一样的 for i in line: f.write(i) f.writelines(line)
文件写入的两种模式之 【wb】模式
# 写入的是字节,因此当我们在写入的时候创建了 # 一个字符串需要先进行编码才能够进行写入 with open('user_utf-8', 'wb') as f: f.write('中国你好好!'.encode('utf-8'))
(3).a只写模式:在文件不存在的时候创建,文件存在指针直接跳到文件结尾,追加写入文件,和w的区别就是一个是清空写入,一个是追加写入,其他的都是一样的。
例题:做一个简单的拷贝文件的工具
# 拷贝文件的小工具 src_file = input('源文件路径>>').strip() dst_file = input('目的文件路径>>').strip() with open(src_file, 'rb') as read_f, open(dst_file, 'wb') as write_f: for line in read_f: write_f.write(line)
3. 文件内光标的移动
光标的移动在【rt】模式下是是字符为单位的,但是在【rb】的形式下是以字节为单位的
# rt模式 读的是字符 with open('user_utf-8', 'rt', encoding='utf-8') as f: data = f.read(3) print(data) # rb模式,读的是字节,如果想显示出原始的字符,得先进行解码 with open('user_gbk', 'rb') as f: # data = f.read(3) # b'\xe4\xb8\xad' data = f.read(2) print(data, data.decode('gbk'))
控制文件指针移动的方法:
f.seek(参数一, 参数二) 参数一: 指的是移动的字节数 参数二:0 模式是默认模式,在任何的打开方式下都可以使用,但是1,和2 只能在b模式下才可以进行使用 0:文件指针以文件开头为参照移动【参数一】个字节数,移动的字节数不能为负 1: 文件指针以当前指针所在位置为参照移动【参数一】个字节数, 负数为左,正数为右 2: 文件指针以文件末尾为参照移动【参数一】个字节数
f.tell()
查看当前指针离文件头部的字节数
0模式:
# f.seek的0模式,f.seek的指针都是以字节形式移动的 # 在我们人为操作移动的过程中,不能把一个字符给拆分开 # 否则在打印的时候会报错 # rt模式 with open('user_utf-8', 'rt', encoding='utf-8') as f: f.read() f.seek(3, 0) print(f.tell()) print(f.read()) # rb模式 with open('user_utf-8', 'rb') as f: f.seek(3, 0) print(f.tell()) print(f.read().decode('utf-8'))
1 模式
# f.seek的1模式, # 1.只能在b模式下进行使用 # 2.偏移量可负可正,负为左,正为右 # 3.指针移动不能拆分字符,否则在解码的时候会报错 with open('user_utf-8', 'rb') as f: f.read() f.seek(-3, 1) print(f.read().decode('utf-8'))
2 模式
# f.seek的2模式 # 1. 只能在b模式下使用 # 2. 偏移量可正可负,正返回为空,负代表指针移动 # 3.指针移动不能拆分字符,否则在解码的时候会报错 with open('user_utf-8', 'rb') as f: f.seek(-3, 2) print(f.read().decode('utf-8'))
例题:tail -f access.log 模拟当前命令
command = input('请输入命令(Q退出)>>').strip() while True: try: if command.upper() == 'Q': break if command.split()[0] == 'tail' and command.split()[1] == '-f': # 输入的命令没有错误,获取文件名 file_path = command.split()[2] print(file_path) with open(file_path, 'rb') as f: # 移动指针到尾部 f.seek(0, 2) while True: line = f.readline() # 如果没有文件导入,就继续循环 if len(line) == 0: continue else: # 如果有文件导入就写入文件 print(line.decode('utf-8')) else: print('usage: tail -f file_path!') except: print('usage: tail -f file_path!')
4. 文件的修改
文件就是计算机的操作系统给我们映射的一块硬盘空间。对于硬盘而言,是没有办法修改的,我们对于硬盘的操作也只能是覆盖写入,因此文件也是不能修改的。但是我们会发现,我们每次打开文件的是可以对其进行的修改的,这究竟是怎么回事呢?是因为内存。我们的数据在硬盘上是没有办法修改,但是在内存中确是可以进行修改的,因此我们通常所说的文件修改其实指的就是内存的修改。通过内存修改完成之后重新写入硬盘中的。
文件修改的两种方式:
1. 把文件全部加载到内存中,然后在内存中修改我们的数据,之后统一的写入文件中
优点:在文件修改过程中同一份数据只有一份
缺点:会占用过多的内存
2. 把文件一行一行的加载到内存中,一行行的修改之后写入到一个新的文件,当修改完成之后,删除源文件,然后把新的文件名字改成源文件的名字。
优点:不会占用过多的内存
缺点:在文件修改过程中,会有两份数据存在硬盘中。
验证硬盘里的数据是不能修改的:
文件内容:
你好,啊slegeg
我好
大家好
# 文件内容: ''' 你好,啊slegega 我好 大家好 ''' with open('user_utf-8', 'r+t', encoding='utf-8') as f: # 移动指针到第一行的【啊】后面 f.seek(12, 0) # 写入【中国好】三个字 # 如果硬盘数据能够进行修改第一行一概出现:你好,啊中国好slegega # 如果硬盘不能改只能覆盖,应该出现:你好,啊中国好我好(因为把这一行后面的换行符也去掉了) f.write('中国好')
文件的修改方法:
文件内容:
kevin is dsb dsb is kevin alex is kevin
第一种方式的把kevin全部改成SB
# 内容全部加载到内存 with open('a.txt', 'rt', encoding='utf-8') as f: res = f.read().replace('kevin', 'SB') # 将修改的数据重新写入文件中 with open('a.txt', 'wt', encoding='utf-8') as f: f.write(res)
第二种方式把所有‘SB’全部改成kevin
# 首先打开以rt得方式打开源文件,然后以wt的形式打开一个新文件 with open('a.txt', 'rt', encoding='utf-8') as read_file,\ open('.a.txt.swap', 'wt', encoding='utf-8') as write_file: # 修改一个值并写入到一个新的文件中 for line in read_file: res = line.replace('SB', 'kevin') write_file.write(res) import os os.remove('a.txt') os.rename('.a.txt.swap', 'a.txt')