一、基本概念
1.操作系统与文件
1)操作系统
从计算机用户的角度来说,计算机操作系统体现为其提供的各项服务;从程序员的角度来说,其主要是指用户登录的界面或者接口;如果从设计人员的角度来说,就是指各式各样模块和单元之间的联系
目前有的操作系统有windows、mac、linux等
2)文件
计算机文件是以计算机硬盘为载体存储在计算机上的信息集合。是操作系统提供给用户或者说应用程序操作硬盘的一种功能
双击文件:硬盘转,磁头读取数据
保存文件:硬盘转,磁头写入数据
# 我们在操作文件的时候其实操作的是硬盘
'''文件其实是操作系统暴露给我们可以简单快捷的操作硬盘的接口'''
2.绝对路径与相对路径
1)绝对路径
好比人所处的位置,非常详细的路径描述,无论什么人按什么位置都可以找到
D:\Python38\include\cpython\a.txt
2)相对路径
要有一个参考,只有对应的人才可以找到
a.txt
二、文件处理
1.基本步骤
# 计算机三层体系结构:应用程序、操作系统、计算机硬件(硬盘)
1)打开文件,由应用程序向操作系统发起系统调用open(...),操作系统从对应一块硬盘空间获取文件并打开,并返回一个文件对象赋值给一个变量f
f = open('a.txt', 'r', encoding = 'utf-8')
print(f) # 文件对象、文件句柄
2)调用文件对象下的读/写功能,会被操作系统转化为读/写硬盘的操作
msg = f.read()
msg = f.write()
3) 向操作系统发起关闭请求,回收操作系统
f.close()
2.with语法
f = open(r'a.txt','r',encoding='utf8') # 打开a.txt 使用变量名f指代改文件
print(f.read())
f.close() # 回收操作系统打开的文件资源
del f # 回收应用程序级的变量,一定发生在f.close() 之后,否则就会导致操作系统打开的文件无法关闭,白白占用资源
1)python提供了with关键字来管理上下文,自动垃圾回收,避免忘记f.close(),占用资源
with open(r'a.txt','r',encoding='utf8') as f:
print(f.read()) # 读取文件内容
# with子代码运行结束之后会自动调用close关闭文件资源
"""
书写形式:with open(文件路径,读写模式,编码格式) as 变量名:
子代码块
注意:文件路径是必须的,读写模式和编码格式是可选的
"""
# 如果不指定读写模式,那么默认使用r
# 如果不指定编码格式,那么默认使用当前计算机内部默认编码
"""在中国所有的windows电脑内部默认的编码是gbk"""
with open(r'a.txt') as f:
print(f.read()) # 读取文件内容
2)取消转义
res = r'D:\day08\a.txt'
res1 = r'D:\day08\n.txt' # 取消换行
res2 = r'D:\day08\t.txt' # 取消水平制表符
res3 = r'D:\day08\v.txt' # 取消垂直制表符
res3 = r'D:\day08\r.txt' # 取消回车
三、文件打开
1.控制文件读写操作的模式
1) r(默认的):只读,如果文件不存在则报错,文件存在则文件指针处于文件开头
with open('a.txt', mode = 'r', encoding = 'utf-8') as f:
res = f.read() # 会将文件的内容由硬盘全部读入内存,赋值给res
# # print(f.read())
# # print('='*50)
# # print(f.read()) # 无结果,因为f已经读完,指针在最后,后面无内容
# print(f.readable()) # out>>> True
# print(f.writable()) # out>>> False
2) w:只写,如果文件不存在则建立空文档,文件存在则清空,文件指针处于文件开头
with open('b.txt', mode = 'w', encoding = 'utf-8') as f:
# f.write("richer\n") # \n 换行符
# f.write("hello my friend\n")
# f.write("come on")
f.write("richer\nhello my friend\ncome on") # 合并上面三行代码,如过没有换行符上述三行代码将写在一行 等价于f.write("richer hello my friend come on")
# # print(f.readable()) # out>>> False
# # print(f.writable()) # out>>> True
总结:w模式,在打开了文件不关的情况下,连续的write写入,新写的内容永远跟在后面
3) a:只追加写,如果文件不存在则创建空文档,文档存在不会清空,文件指针处于文件的末尾
with open('c.txt', mode = 'a', encoding = 'utf-8') as f:
f.write("444\n")
f.write("555\n")
f.write("666\n")
print(f.readable()) # out>>> False
print(f.writable()) # out>>> True
总结:a模式在文件打开不关的情况下,连续write写入新的内容永远跟在后面,这一点与w模式相同
不同点,在文件关闭后重新打开的情况下,a模式永远写在后面,而w模式则是覆盖掉原来的文件
2.控制文件读写内容的模式
'''大前提: tb模式均不能单独使用,必须与r/w/a之一结合使用'''
1) t(默认的):读写都是以字符串为单位的,只适用于文件文件,必须指定encoding参数
# 如果我们指定的文件打开模式为e/w/a,其实默认为
with open('a.txt', mode = 'rt', encoding = 'utf-8') as f:
res = f.read()
print(type(res)) # out>>> <class 'str'>
with open('a.txt', mode = 'wt', encoding = 'utf-8') as f:
s = 'abc'
f.write(s) # 读出的是字符串类型,则写入的也必须是字符串类型
# 强调:t 模式只能用于操作文本文件,无论读写,都应该以字符串为单位,而存取硬盘本质都是二进制的形式,当指定 t 模式时,内部帮我们做了编码与解码
2)b:读写都是以bytes为单位的,适用于所有文件,一定不能指定encoding参数
with open('1.mp4', mode = 'rb') as f: # 可以读取视频
res = f.read() # 当文件小,读出的量小,使用f.read,当文件过大不要用f.read一次性读出
print(res.decode('utf-8')) # out>>> False 视频不能解码,视频的内容与字符编码没有关系,但是原文件是a.txt,便可以解码
with open('a.txt',mode='rb') as f:
res = f.read()
print(res.decode('utf-8')) # out>>> True
with open('a.txt',mode='ab') as f:
f.write("你好 世界".encode('utf-8')) # 针对文本文件t模式更方便一些
案例:文件拷贝功能
# 1.不考虑文件很大的情况下
with open('1.mp4',mode='rb') as f1,open(r'D:\1111111.mp4',mode='wb') as f2:
# res = f1.read()
# f2.write(res)
f2.write(f1.read()) # 将上面两行代码合并
# 2.考虑文件很大的情况下
# 知识储备
# with open('a.txt', mode = 'rt', encoding = 'utf-8') as f:
# # f.read() # 文件太大,不要直接read,不然会导致内存直接溢出,计算机变得很卡
# for line in f: # 一行一行读
# print(line, end = ' ') # end 把打印自动换行符给去掉,只留文件自带换行符
# with open('1.mp4', mode = 'rb') as f:
# for line in f:
# print(line)
# 具体实现
with open('1.mp4', mode = 'rb') as f1, open(r'D:\1111111.mp4, mode = 'wb') as f2:
for line in f1:
f2.write(line)
其他模式:可读可写
# r+t
# w+t
# a+t
# r+b
# w+b
# a+b
# with open('a.txt',mode='r+t',encoding='utf-8') as f:
# print(f.readable()) # out>>> True
# print(f.writable()) # out>>> True
# print(f.read()) # out>>> True
# f.write("22222222222222222222\n")
# with open('a.txt',mode='w+t',encoding='utf-8') as f:
# print(f.readable()) # out>>> True
# print(f.writable()) # out>>> True
四、操作文件的方法
# a.txt : # 三行字符
# 哈哈哈
# 嘿嘿嘿
# 嘻嘻嘻
1.读操作
f.read() # 读取所有内容,执行完该操作后,文件指针会移动到文件末尾
f.readline() # 一次读取一行内容,指针移动到第二行首部,类似于for循环
f.readlines() # 读取每一行内容,存放于列表中
with open('a.txt',mode='rt',encoding='utf-8') as f:
# print(f.readline()) # out>>>哈哈哈
# print(f.readline()) # out>>>嘿嘿嘿
lines = f.readlines()
print(lines) # out>>> ['哈哈哈\n', '嘿嘿嘿\n','嘻嘻嘻\n]
with open('a.txt',mode='rb') as f:
lines = f.readlines()
print(lines) # out>>> [b'\xb9\xfe\xb9\xfe\xb9\xfe\n',b'\xce\xfb\xce\xfb\xce\xfb\n',b'\xba\xd9\xba\xd9\xba\xd9\n']
2.写操作
with open('a.txt',mode='wt',encoding='utf-8') as f:
f.write("111\n222\n333\n") # 针对文本模式的写,需要自己写换行符
# f.write("111\n222\n333\n",encode('utf-8')) # 针对b模式的写,需要自己写换行符以及解码
# lines = ['111\n','222\n','3333\n']
# for line in lines:
# f.write(line)
f.writelines(lines) # 传给f.writelines的类型是能被for循环循环的类型
f.write('hello') # 写了一次
f.flush() # 刷新 实时需要时用,但降低计算机运行效率
f.writelines('hello') # 写了五次
五、文件指针移动
'''大前提:只有t模式下的,f.read(n)中的n代表的是字符个数,除此以外,关于指针的移动,单位都是字节bytes'''
# a.txt :hello你好 # 7个字符,11个字节
1.读内容f.read()
with open('a.txt',mode='rt',encoding='utf-8') as f:
res = f.read(3)
print(res) # out>>> hel
res = f.read(6)
print(res) # out>>> hello你 证明t模式下read(n)都是字符
with open('a.txt', mode = 'rb') as f:
res = read(6)
print(res) # 报错
res = read(8)
peint(res.decode('utf-8')) # out>>> hello你
2.截断文件(删除文件内容)f.truncate()
'''是文件写操作,内容从某个位置开始到某个位置结束留下,其他的都删除'''
# r/w模式截文件都不可以,a/r+都不清文件,所以都可以截取文件内容
with open('a.txt',mode='rt',encoding='utf-8') as f:
f.truncate(6) # out>>> hello?
3.只动指针f.seek()
'''移动的全都是字节个数'''
# f.seek(用动的字节个数,模式)
f.seek(字节个数,0) # 0 模式:参照文件开头移动
f.seek(字节个数,1) # 1 模式:参照当前指针位置移动
f.seek(字节个数,2) # 2 模式:参照文件末尾移动,即倒着移动,通常都是负几
# ps:只有0模式可以t下使用,其中1和2模式只能在b模式下使用,但是无论在t模式还是b模式下,移动的都是字节个数
1)0 模式
with open('a.txt', mode = 'rb') as f:
f.seek(9,0)
f.seek(3,0)
print(f.tell()) # out>>> 3 告诉你指针在哪
# 当前指针位置在第3个字节,因为0 模式永远参照文件开头
2)1 模式
with open('a.txt', mode = 'rb') as f:
f.seek(3,1)
f.seek(4,1)
# 当前指针在第7个字节,从当前位置3,移动了4个字节
3)2 模式
with open('a.txt',mode='rb') as f:
f.seek(0,2)
f.seek(-3,2)
print(f.read().decode('utf-8')) # out>>> 好
# 当前指针位置,首先跳到文件末尾,参照文件末尾移动3个字符
航海日志
# 创建日志
access.log
# 记录日志
import time
with open('access.log', mode='at', encoding='utf8') as f:
f.write("%s 张三 200.103.110.22 ok \n" % time.striftime("%Y-%m-%d %H:%M:%S"))
# tail 监控
with open('access.log', mode='rb') as f
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
continue
else:
print(line.encode='utf8',end=' ') # end=' ' 去掉换行符\n
六、文件修改
'''
文件修改的原理:
把硬盘数据读入内存,在内存修改完毕后,再覆盖回硬盘
'''
# 方案一
# 将文件内容一次性读入内存,然后在内存中修改完毕后再覆盖原文件
with open('test.txt', mode='rt', encoding='utf8') as f:
data = f.read()
with open('test.txt', mode='wt', encoding='utf8') as f:
f.write(data.replace('richer','RICHER'))
# 优点:在文件修改过程中同一份数据只有一份
# 缺点:会过多占用内存
# 方案二
# 以读的模式打开原文件,以写的方式打开一个临时文价,一行行读取原文件内容,修改完毕后写入临时文件,然后删掉原文件,将临时文件重命名为原文件名
import os
with open('test.txt', mode='rt', encoding='utf8') as f1,\
open('.test.txt.swp', mode='wt', encoding='utf8') as f2:
for line in f1:
f2.write(line.replace('EGON',"egon"))
os.remove('test.txt')
os.rename('.test.txt.swp', 'test.txt')
# 优点:不会占用过多的内存
# 缺点:在文件修改过程中同一份数据存了两份