1、什么是文件
文件是操作系统提供给用户或应用程序的一种虚拟单位,该虚拟单位直接映射的是硬盘空间。通俗点说,文件就是存放数据的地方
2、为何要处理文件
用户或应用程序直接操作文件(读/写)就被操作系统转换成具体的硬盘操作,从而实现将内存中的数据永久保存到硬盘中
3、使用文件
通常,我们使用电脑的时候,例如编写了一段代码,我们要把这段代码保存在硬盘上,方便下次使用。在Python中,要打开这个文件,需要三个步骤:
1)找出文件存放的路径,打开文件
2)对文件进行读写操作
3)关闭文件
说到找出文件的存放路径,就会引入相对路径和绝对路径的问题。在Windows中,相对路径指的是相对于当前执行文件所在的文件夹开始查找所需的文件,绝对路径是指从盘符开始直到这个文件的位置,写一个完整的路径。在Python中文件路径有两种表示方式,以我电脑上 python3.6.6 文件为例:
Python绝对路径写法:用双反斜线或者斜线区分层次
E:\Python\download\python-3.6.6-amd64.exe
E:/Python/download/python-3.6.6-amd64.exe
Python相对路径写法:
如果我从download文件夹对这个文件操作,相对路径写为:python-3.6.6-amd64.exe
4、文件的打开模式
f = open(r'a.txt', mode='r', encoding='utf-8') # 打开文件
data = f.read() # 对文件进行读操作
f.close() # 关闭文件
r:只读模式,打开文件默认是只读模式,文件不存在打开会报错,如果文件存在文件指针跳到文件的开头
w:只写模式,文件不存在则创建,文件存在则覆盖
a:追加模式,文件不存在则创建,文件存在则不会覆盖,写内容会以追加的方式写(写日志文件的时候常用),追加模式是一种特殊的写模式
t:文本模式,只能针对文本文件,读写文件都是以字符串为单位的,必须指定 encoding 参数
b:二进制模式,文件以二进制的方式打开,读写文件都是以 bytes 为单位的,必须与上面的三种模式在一起使用,即rb,wb,ab,这种方式后面不用指定 encoding 参数
文件的打开还有一种方式,即上下文管理:
with open(r"a.txt", "rt", encoding = "utf-8") as f:
data=f.read()
这种方式无需手动关闭文件
5、文件的读写操作
read():对文件进行读操作,一次性读取全部文件内容
readline():每次读取一行
readlines():将每行内容作为列表元素,返回的是一个列表
readable():判断文件是否可读
write():对文件进行写操作
writelines():可以写一个序列,比如列表,会迭代写入文件(后面会学到迭代)
writeable():判断是否可写
6、文件内指针移动
大前提:文件内指针的移动是以字节Bytes为单位的,唯独 t 模式下的 read 读取内容是以字符为单位
# a.txt文件里存放内容:
# 你好啊aaaa哈哈哈
with open("a.txt", "rt", encoding="utf-8") as f:
data = f.read(3)
print(data)
# 输出:
# 你好啊
with open("a.txt", "rb") as f:
data = f.read(3)
print(data.decode("utf-8"))
# 输出:
# 你
f.seek(指针移动的字节数, 模式控制): 控制文件指针的移动
模式控制:
0:默认的模式,该模式代表指针移动的字节数是以文件开头作为参照的
1:该模式代表指针移动的字节数是以当前所在的位置作为参照的
2:该模式代表指针移动的字节数是以文件末尾的位置作为参照的
强调:其中0模式可以在 t 或者 b 模式使用,而1和2模式只能在 b 模式下用
f.tell():查看文件指针当前距离文件开头的位置
0模式详解:指针移动的字节数以文件开头作为参照,要注意如果文件中有中文字符,光标移动一定是3的倍数
# a.txt文件中存放:
# 你好啊aaaa哈哈哈
with open("a.txt", "rt", encoding="utf-8") as f:
f.seek(9, 0)
print(f.tell())
print(f.read())
# 输出:
# 9
# aaaa哈哈哈
1模式详解:指针移动的字节数以当前指针所在位置作为参照
with open("a.txt", "rb") as f:
f.seek(3, 1)
print(f.tell())
f.seek(10, 1)
print(f.tell())
print(f.read().decode("utf-8"))
# 输出:
# 3
# 13
# 哈哈哈
2模式详解:指针移动的字节数以文件的末尾位置作为参照
with open("a.txt", "rb") as f:
f.seek(-9, 2)
data = f.read()
print(data.decode("utf-8"))
# 输出:
# 哈哈哈
小练习:向文件里不断地添加日志信息,将日志的最后一行打印输出到屏幕上,每次都能打印最新添加的信息
# exercise.py
with open("access.log", "rb") as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
continue
else:
print(line.decode("utf-8"), end="")
# run.py
import time
with open("access.log", "a+", encoding="utf-8") as f:
f.write("%s 下雨了
" %time.strftime("%Y-%m-%d %X"))
# 每运行一次 run.py,都会打印获取系统当前时间
# 运行:
# 2018-09-21 18:06:11 下雨了
# 2018-09-21 18:06:12 下雨了
# 2018-09-21 18:06:13 下雨了
7、文件修改
1)硬盘空间无法修改,硬盘中的数据更新都是用新的内容覆盖旧的内容,内存控制可以修改
2)文件对应的是硬盘空间,硬盘不能修改,即文件本质也是不能修改的,但是我们看到的文件内容可以修改,这是把硬盘中的文件内容读入内存,然后在内存中修改完毕后再覆盖回硬盘
有两种实现方式:
1)将文件内容一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
优点:在文件修改过程中同一份数据只有一份,不会过多的占用硬盘空间
缺点:会过多地占用内存
# a.txt中存放的内容是:
# 你好啊aaaa哈哈哈
# 现在将aaaa改为bbbb
with open("a.txt", "r", encoding="utf-8") as f:
data = f.read()
with open("a.txt", "w", encoding="utf-8") as f:
f.write(data.replace("aaaa", "bbbb"))
# 运行:
# 你好啊bbbb哈哈哈
2)以读的方式打开原文件,以写的方式打开一个临时文件,将原文件一行一行读入内存,修改完后写入临时文件,然后再删除原文件,将临时文件重命名为原文件名
优点:不会占用过多的内存
缺点:在文件修改过程中同一份数据存了两份,硬盘空间不足将无法完成修改
# 现在a.txt里存放了内容是:
# 你好啊bbbb哈哈哈
# 将bbbb改为aaaa
import os
with open("a.txt", "r", encoding="utf-8") as f1,
open("a_temp.txt", "w", encoding="utf-8") as f2:
for line in f1:
f2.write(line.replace("bbbb", "aaaa"))
os.remove("a.txt")
os.rename("a_temp.txt", "a.txt")
# 运行:
# 你好啊aaaa哈哈哈