文件操作
初识文件操作
使用python来读写文件是非常简单的操作,我们使用open()函数来打开某个文件,获取到文件句柄,然后通过文件句柄就可以进行各种各样的操作了。根据打开形式的不同能够执行的操作也会有相应的差异。操作文件的方式一般有如下:
r, w, a, r+, w+, a+, rb, wb, ab, r+b, w+b, a+b
默认使用的是r(只读)模式
只读操作(r, rb)
f = open("python", mode="r", encoding="utf-8")
content = f.read()
print(content)
f.close()
python.txt
这是python文件
运行结果:
这是python文件
Process finished with exit code 0
需要注意encoding表示编码集,根据文件的实际保存编码进行获取数据,对于我们来说,使用更多的是utf-8。
rb. 读取出来的数据是bytes类型,,在rb模式下,不能选择encoding字符集。
f = open("python", mode="rb")
content = f.read()
print(content)
f.close()
python.txt
这是python文件
运行结果:
b'\xe8\xbf\x99\xe6\x98\xafpython\xe6\x96\x87\xe4\xbb\xb6'
Process finished with exit code 0
rb的作用: 在读取非文本文件的时候. 比如读取MP3、图像、视频等信息的时候就需要用到rb。因为这种数据是没办法直接显示出来的. 在后面文件上传下载的时候还会用到。还有,我们看的直播,实际上都是这种数据。
路径
一般分为绝对路径和相对路径:
1. 绝对路径:从磁盘根目录开始一直到文件名。
2. 相对路径:同一个文件夹下的文件,相对于当前这个程序所在的文件夹而言,如果在同一个文件夹中。则相对路径就是这个文件名,如果在上一层文件夹,则要使用../表示上一层文件,如果在上多层文件夹中,则需要使用多次../。
一般在开发过程中推荐大家使用相对路径。因为在我们把程序拷贝给别人使用的时候. 直接把整个项目文件拷贝出去就能运行,但是如果使用绝对路径,那还需要拷贝外部的文件。
获取文件
read()
将文件中的内容全部读取出来。弊端:占内存。如果文件过大,容易导致内存崩溃,使用时应该小心谨慎。
f = open("../FileOne/静夜思.txt", mode="r", encoding="utf-8")
content = f.read()
print(content)
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
运行结果:
床前明月光
疑是地上霜
举头望明月
低头思故乡
Process finished with exit code 0
read(n)
读取n个字符,需要注意的是,如果再次读取,那么会在当前位置继续去读而不是从头读,如果使用的是rb模式,则读取出来的是n个字节。
f = open("../FileOne/静夜思.txt", mode="r", encoding="utf-8")
content = f.read(4)
contentOne = f.read(5)
print(content)
print(contentOne)
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
运行结果:
床前明月
光
疑是地
Process finished with exit code 0
值得注意的是,在这里换行符表示一个字节。前面4个字节,后面接着输出5个字节。
f = open("../FileOne/静夜思.txt", mode="rb")
content = f.read(4)
contentOne = f.read(5)
print(content)
print(contentOne)
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
运行结果:
b'\xe5\xba\x8a\xe5'
b'\x89\x8d\xe6\x98\x8e'
Process finished with exit code 0
readline()
一次读取一行数据,注意:readline()结尾,注意每次读取出来的数据都会有一个\n 。所以呢,需要我们使用strip()方法来去掉\n或者空格,当然,我们也可以在print后面加上end=""去掉空格。
f = open("../FileOne/静夜思.txt", mode="r", encoding="utf-8")
contentOne = f.readline()
contentTwo = f.readline()
contentThree = f.readline()
contentFour = f.readline()
print(contentOne.strip())
print(contentTwo.strip())
print(contentThree, end="")
print(contentFour, end="")
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
运行结果:
床前明月光
疑是地上霜
举头望明月
低头思故乡
Process finished with exit code 0
readlines()
将每一行形成一个元素,放到一个列表中,将所有的内容都读取出来,所以也是,容易出现内存崩溃的问题,一般不推荐不推荐使用。
f = open("../FileOne/静夜思.txt", mode="r", encoding="utf-8")
lst = f.readlines()
print(lst)
for line in lst:
print(line.strip())
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
['床前明月光\n', '疑是地上霜\n', '举头望明月\n', '低头思故乡']
床前明月光
疑是地上霜
举头望明月
低头思故乡
Process finished with exit code 0
从列表里面我们可以看出,每次获取的行后面都会有换行符/n。因此,打印过程中我们应该使用strip()或者end = ()去掉换行。
循环读取
f = open("../FileOne/静夜思.txt", mode="r", encoding="utf-8")
for line in f:
print(line.strip())
静夜思.txt
床前明月光
疑是地上霜
举头望明月
低头思故乡
运行结果:
床前明月光
疑是地上霜
举头望明月
低头思故乡
Process finished with exit code 0
这种方式是事先就组好了,每次读取一行的内容,不会产生内存溢出的问题。
注意:
在每次读取完文件时,应该关闭文件句柄。f.closed()
在执行操作过后可使用刷新机制对文件进行刷新。f.flush()
写模式(r,rw)
写的时候注意,如果没有文件,则会创建文件,如果文件存在,则将原件中原来的内容删除,再写入新内容。
f = open("⼩娃娃", mode="w", encoding="utf-8")
f.write("⾦⽑狮王")
# f.read() # 尝试读取文件,此时只是写,抛出io.UnsupportedOperation: not readable
f.flush() # 刷新. 养成好习惯
f.close()
创建了文件:小娃娃
⾦⽑狮王
运行结果:
Process finished with exit code 0
本次文件写操作执行完毕后,程序结束,控制台没有输出值,只是在列表中创建了文件。
f = open("⼩娃娃", mode="wb")
f.write("⾦⽑狮王".encode("utf-8"))
f.flush()
f.close()
创建文件:小娃娃
⾦⽑狮王
运行结果:
Process finished with exit code 0
wb模式下,可以不指定文件的编码,但是在写文件的时候必须将字符串转换为utf-8的bytes数据,如果不转化,将会出现一下的错误。
TypeError: a bytes-like object is required, not 'str'
追加(a,ab)
在追加模式下. 我们写入的内容会追加在文件的结尾.
f = open("⼩娃娃", mode="a", encoding="utf-8")
f.write("麻花藤的最爱")
f.write("是小学生")
f.flush()
f.close()
创建文件:小娃娃
麻花藤的最爱是小学生
运行结果:
Process finished with exit code 0
f = open("⼩娃娃", mode="ab")
f.write("麻花藤的最爱".encode())
f.write("是小学生".encode())
f.flush()
f.close()
创建文件:小娃娃
麻花藤的最爱是小学生
运行结果:
Process finished with exit code 0
由于编译器默认的是utf-8,所以在小娃娃文件中显示的是未改变的字符。
读写模式(r+,r+b)
对于读写模式,必须是先读。因为默认光标是在开头的,准备读取的,当读完了之后再进行写入,我们以后使用频率最高的模式就是r+。
f = open("⼩娃娃", mode="r+", encoding="utf-8")
content = f.read()
f.write("麻花藤的最爱")
print(content)
f.flush()
f.close()
运行前的文件:小娃娃
麻花藤的最爱
运行后的文件:小娃娃
麻花藤的最爱麻花藤的最爱
运行结果:
麻花藤的最爱
Process finished with exit code 0
在正常的读取后,文件的写入在结尾。
下面演示错误操作:
f = open("⼩娃娃", mode="r+", encoding="utf-8")
f.write("哈哈")
content = f.read()
print(content)
f.flush()
f.close()
运行前的文件:小娃娃
麻花藤的最爱
运行后的文件:小娃娃
哈哈藤的最爱
运行结果:
藤的最爱
Process finished with exit code 0
在没有任何操作之前,默认的光标在开头,当写入“哈哈”以后,“麻花”二字被覆盖,且光标往后移动了两个位置,默认读取从光标后开始读取。
总结,在r+模式下,必须是先读取,再写入。
写读(w+,w+b)
先将所有的内容清空,然后写入,最后读取,但是读取的内容是空的,一般不常用。
f = open("⼩娃娃", mode="w+", encoding="utf-8")
f.write("哈哈")
content = f.read()
print(content)
f.flush()
f.close()
运行前的文件:小娃娃
麻花藤的最爱
运行后的文件:小娃娃
哈哈
运行结果:
Process finished with exit code 0
那么可能有同学会问,先读不就好了么?
错。理由:w+ 模式下, 一开始读取不到数据,然后写的时候再将原来的内容清空,所以这种操作方式很少用。
追加读(a+)
a+模式下,不论先读还是后读,都是读取不到数据的。
f = open("⼩娃娃", mode="a+", encoding="utf-8")
f.write("麻花藤")
content = f.read()
print(content)
f.flush()
f.close()
运行前的文件:小娃娃
爱笑的眼睛
运行后的文件
爱笑的眼睛麻花藤
运行结果:
Process finished with exit code 0
还有一些其它带b的操作,就不多赘述了,就是把字符换成字节,仅此而已。
其它相关操作
seek(n)
光标移动到n位置,注意,移动的单位是byte,所以如果是utf-8的中文部分要是3的倍数。
通常我们使用seek都是移动到开头或者结尾。
移动到开头:seek(0) 。郑州人流价格 http://www.zzzykdfk.com/
移动到结尾:seek(0,2),seek的第一个参数表示的是从哪个位置进行偏移,默认是0,表示开头,1表示当前位置,2表示结尾。
f = open("⼩娃娃", mode="r+", encoding="utf-8")
f.seek(0) # 光标移动到开头
content = f.read() # 读取内容, 此时光标移动到结尾
print(content)
f.seek(0) # 再次将光标移动到开头
f.seek(0, 2) # 将光标移动到结尾
content2 = f.read() # 读取内容. 什么都没有
print(content2)
f.seek(0) # 移动到开头
f.write("张国荣") # 写⼊信息. 此时光标在9 中⽂3 * 3个 = 9
f.flush()
f.close()
运行前的文件:小娃娃
123456789
运行后的文件:小娃娃
张国荣
运行结果:
123456789
Process finished with exit code 0
tell()
获取到当前光标位置。
f = open("⼩娃娃", mode="r+", encoding="utf-8")
f.seek(0) # 光标移动到开头
content = f.read() # 读取内容, 此时光标移动到结尾
print(content)
f.seek(0) # 再次将光标移动到开头
f.seek(0, 2) # 将光标移动到结尾
content2 = f.read() # 读取内容. 什么都没有
print(content2)
f.seek(0) # 移动到开头
f.write("张国荣") # 写⼊信息. 此时光标在9 中⽂3 * 3个 = 9
print(f.tell()) # 光标位置9
f.flush()
f.close()
运行前的文件:小娃娃
123456789
运行后的文件:小娃娃
123456789
9
Process finished with exit code 0
truncate()
截断文件光标后的内容,日常操作过程中几乎不用。
f = open("小娃娃", mode="w", encoding="utf-8")
f.write("哈哈") # 写⼊两个字符
f.seek(3) # 光标移动到3, 也就是两个字中间
f.truncate() # 删掉光标后⾯的所有内容
f.close()
运行前的文件:小娃娃
麻花藤最爱的人
运行后的文件
哈
运行结果:
Process finished with exit code 0
深坑请注意:在r+模式下,如果读取了内容,不论读取内容多少,光标显示的是多少,再写入或者操作文件的时候都是在结尾进行的操作。
所以如果想做截断操作,记住了,要先挪动光标,挪动到你想要截断的位置,然后再进行截断关于truncate(n), 如果给出了n. 则从开头开头进行截断,如果不给n,则从当前位置截断,后面的内容将会被删除。
修改文件以及另一种打开文件的方式
import os
with open("⼩娃娃", mode="r", encoding="utf-8") as f1, \
open("⼩娃娃_new", mode="w", encoding="UTF-8") as f2:
content = f1.read()
new_content = content.replace("冰糖葫芦", "⼤⽩梨")
f2.write(new_content)
os.remove("⼩娃娃") # 删除源⽂件
os.rename("⼩娃娃_new", "⼩娃娃") # 重命名新⽂件
弊端:一次将所有内容进行读取,导致内存溢出,解决⽅案: 一行一行的读取和操作。
import os
with open("⼩娃娃", mode="r", encoding="utf-8") as f1, \
open("⼩娃娃_new", mode="w", encoding="UTF-8") as f2:
for line in f1:
new_line = line.replace("⼤⽩梨", "冰糖葫芦")
f2.write(new_line)
os.remove("⼩娃娃") # 删除源⽂件
os.rename("⼩娃娃_new", "⼩娃娃") # 重命名新⽂件
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。