文件操作
# 文件的介绍
# 文件概念
文件是操作系统提供给用户或应用程序,操作硬盘的一种虚拟的接口。
# 文件作用
可以通过文件将数据永久保存到硬盘中,操作文件就是在间接操作硬盘。
用户操作文件,都是在向操作系统发起系统调用,然后将其转换成具体的硬盘操作。
# 文件操作
python中可以使用open()
函数来打开文件,并获取到文件句柄用于控制操作系统来操作文件。
# 打开文件的资源占用
open()
函数会让操作系统打开一个文件,然后变量名会指向打开的文件对象。
文件也是一种对象类型,所以需要赋值给变量名,以存放文件对象(句柄)。
文件对象又称为文件句柄,用来控制操作系统来进行文件操作。就像控制游戏的游戏手柄一样。
文件对象(句柄)可以控制操作系统操作文件,我们执行的操作会映射到硬盘空间中。
打开文件会占用内存,以便我们对文件进行操作。
# 文件基本操作流程
# 介绍
应用程序对文件的操作请求,都是在向操作系统发送系统调用,然后由操作系统控制硬盘完成相应操作。
# 打开文件
file = open("文件路径", mode="操作模式", encoding="utf-8")
文件路径可以是绝对路径,也可以是相对路径。
如果是相对路径,则会在python文件所在路径下寻找文件。
windows路径可以将反斜杠符号转义,使用两个
\\
代替\
。或者在字符串前加r,如r"C:/A/B/C.txt"
。或者直接使用左斜杠,python会自动进行转换。
mode用于指定操作模式。
默认是"rt"。
encoding用于指定编码格式。
linux、mac默认使用utf-8。
windows默认使用gbk。
# 读/写文件
file.read()
读文件内容。
例如:ret = file.read()
file.write("内容")
写文件内容。
例如:file.write("哈哈哈")
# 关闭文件 - 重要
file.close()
关闭操作系统打开的文件,回收操作系统资源。
回收之后file对象仍会存在,但无法再读写。
# 文件模式
# 控制文件读写内容的模式
t
- 文本文件(默认)
读写都以字符串为单位。
只能针对文本文件。会将读到的文本文件二进制数据,转换成文本格式。在进行读写时,会以指定的编码格式,进行编码解码。
必须指定
encoding='utf-8'
,要保证不乱码,就必须指定正确的编码格式。不然读写取str时,会使用默认的编码。
b
- 二进制文件。
可以针对所有文件。
读写都是以bytes为单位。
一定不能指定encoding字符编码。
注意:
t或b不能单独使用,必须和r/w/a连用。
# 控制文件的操作模式
r
- 只读模式 (默认)。
从文件开头开始读,只能读,不可写。
file = open('a.txt', mode='rt', encoding='utf-8')
当文件不存在时会报错。当文件存在时,会打开文件,文件指针跳转到文件开始位置。
w
- 只写模式。
只能写,不可读,清空文件,从文件开头开始写。
通常用于创建新文件,也可以配合读,来copy文件。
file = open('a.txt', mode='wt', encoding='utf-8')
当文件不存在时会创建空文件。当文件存在时,打开并清空文件,文件指针跳转到文件开始位置。
a
- 只追加写模式。
只能写,不可读,不清空文件,从文件末尾开始写。
通常用于已有文件的追加,如日志、用户文件等。
file = open('a.txt', mode='at', encoding='utf-8')
当文件存在时,打开文件!文件指针跳转到文件末尾位置。
当文件不存在时,会创建空文件,文件指针跳转到文件开始位置。
+
模式(了解)
必须配合r/w/a,会在原功能的基础上使其可读可写,了解即可,一般用不上。例如:a+、r+、w+。
x
- 创建写模式 (了解)。
文件存在则创建写,不可读。文件不存在则返回报错。
file = open('a.txt', mode='at', encoding='utf-8')
当文件存在时,则报错,其他和w一样。
当文件不存在时,会创建空文件,文件指针跳转到文件开始位置。
# with上下文管理语法
# 介绍
with语法会在代码块开始时,会自动调用传入的对象的.__enter__()
方法。
在代码块执行完毕后,会自动调用传入的对象的.__exit__()
方法。
文件对象的
.__exit__()
会关闭打开的文件,很方便,所以文件操作一般都会配合with使用。
# 使用例子
# 一次打开一个。
with open(...) as 文件对象名:
文件操作代码
... ...
2
3
4
# 一次打开多个。
with open(...) as 文件对象名1, open(...) as 文件对象名2:
文件操作代码
... ...
2
3
4
# 文件操作的方法
# file.read()
一次性读取所有行内容。
会将文件的所有内容从硬盘读入内存,但读的内容过大时,可能会造成内存溢出。
他会从指针当前位置开始读,全部读完后,文件指针会跳到文件最后一行。
size参数。
可以指定一次读取多少字符/字节,如:
file.read(size=1024)
。
# file.readline()
读取一行,然后文件指针转到下一行。
# file.readlines()
读取文件指针所在行和后面所有行的内容,然后文件指针转到末行。
但读的内容过大时,可能会造成内存溢出。
# for循环取内容 (推荐)
for i in file: ...
会一行一行读写数据,所以一般使用这种方式进行读写,因为更省内存空间,且不会导致内存溢出。
# file.write()
写入内容,并且文件指针转到下一行。
新写的内容,总是跟在旧内容之后,如果需要换行,那么换行符需要自己加。
# file.writelines()
可将可迭代对象的元素取出,每个元素作为一行内容,写入文件中。
例如:
file.writelines([1111, 2222, 3333])
# file.flush()
将file在内存中的缓冲,立刻刷写到硬盘中。
一般不会用,不需要手动去刷写到硬盘。
# 文件的高级操作
# file.tell()
查看当前文件指针位置。
# file.seek(offset, whence)
控制文件指针的移动。无论t模式或者b模式,指针移动的单位都是以字节(bytes)为单位。推荐b模式使用seek移动指针。
offset
- 表示指针移动多少偏移值。
whence
- 0 - 参照物是文件的开头位置(默认)。
- 1 - 参照物是当前指针所在位置。
- 2 - 参照物是文件的末尾位置,参照末尾则offset应该是负的,倒着移动。
例如:
file.seek(10,0)
表示文件指针移动到文件开头第10个字节。linux的tail -f命令可以使用该方式实现。
# 文件修改的两种方式
# 原理
对于硬盘上的数据,在我们修改时,都是用新的数据覆盖老的数据。
而我们平时我们编辑文件的插入,都是先在内存中修改,这时可以插入,也可以覆盖。
而在我们保存文件到磁盘时,就会将内存中的所有内容,覆盖磁盘文件中的所有内容。
# 方式一
文件数据读入到内存进行修改再保存 (性能更高,但文件大时,占用内存也大)。
with open(file_path, "r+", encoding="utf-8") as rfile:
text = rfile.read().replace("asd", "测试")
rfile.seek(0, 0)
rfile.write(text)
2
3
4
# 方式二
文件数据读入一行就修改然后写入一行到临时文件,等全部行修改完后,删除源文件,再将临时文件修改成源文件名 (占用内存少)。
with open(file_path, "rt", encoding="utf-8") as rfile, open(file_swap, "wt", encoding="utf-8") as wfile:
for line in rfile:
wfile.write(line.replace("测试", "asd"))
os.remove(file_path)
os.rename(file_swap, file_path)
2
3
4
5
# CSV格式文件
逗号分隔的存储格式叫做CSV(Comma Separator Values,即逗号分隔值),它是一种通用的、相对简单的文件格式,大部分编辑器都支持直接读入或保存文件为CSV格式。
# CSV一维数据读写
写入
列表就是一维数据,采用join()方法生成逗号分隔的字符串即可。
data = ["北京", "上海", "广州", "深圳"]
with open("data.csv", "wt", encoding="utf-8") as f:
f.write(",".join(data) + "\n")
2
3
读取
with open("data.csv", "rt", encoding="utf-8") as f:
data = f.read().strip("\n").split(",")
2
# CSV二维数据读写
写入
嵌套一层的二维列表就是二维数据,采用循环遍历加join()方法生成逗号分隔的字符串即可。
data = [
["姓名", "年龄", "所在地"],
["张三", "18", "北京"],
["李四", "17", "上海"],
["王五", "20", "广州"],
]
with open("data.csv", "wt", encoding="utf-8") as f:
for i in data:
f.write(",".join(i) + "\n")
2
3
4
5
6
7
8
9
读取
data = []
with open("data.csv", "rt", encoding="utf-8") as f:
for i in f:
data.append(i.strip("\n").split(","))
print(data)
2
3
4
5