Python之文件操作

文件操作

初识文件操作

        使用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) 。      

        移动到结尾: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", "娃娃")  # 重命名新



  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值