初识文件系统:
使用Python 来读写文件是非常简单的操作,我们使用open()函数来打开一个文件,获取到文件句柄,然后通过文件的句柄就可以进行各种各样的操作了,根据打开的不同方式的不同能够执行的操作也会有相应的差异.
打开文件的方式: r (只读) , w(只写) , a(追加) , r+(读写) , w+(写读) , a+(追加写读) , rb , wb , ab , r+b , w+b , a+b . 默认使用的是r(只读)模式
只读操作(r, rb):
f = open("drift.txt", mode="r", encoding="UTF-8")
s = f.read()
print(s)
f.close() # 如果没有这句话, 你在下面的程序中如果删除这个文件. 就会报错
需注意encoding表示编码集,根据文件的实际保存编码进行获取数据,对我们而言,更多的是utf-8.
rb .读取出来的数据时bytes类型,在rb模式下,不能选择encoding字符集.
f = open("drift.txt",mode="rb")
content = f.read()
print(content)
f.close()
注意 : rb 的作用在读非文本文件的时候,比如读取MP3 , 图像,视频等信息的时候就需要用到rb,因为这种数据是没有直接显示出来的,在后面我们上传下载的时候换回用到还有我们看的直播,实际上都是这种数据.
绝对路径和相对路径:
绝对路径: 从磁盘根目录开始一直到文件名.
相对路径:同一文件夹下的文件,相对于当前这个进程所在的文件夹而言,如果在同一文件中,则相对路径就是这个文件名, 如果在上上一层文件夹,则为 ../ 上上层 ../../ 一次类推.
这里推荐大家写代码时使用相对路径,因为我们把程序拷给别人使用的时候,直接将项目拷贝走就可以运行,但是如果用绝对路径,那就还需要拷贝外部的文件. (像输出的确定文件的路径推荐使用绝对路径).
读取文件的方法:
测试文件:
江湖人称漂少
一生中的最爱
1 . read()将文件中的内容全部读取出来,弊端:占内存,如果文件过大,容易导致内存崩溃
f = open("../drift.txt",mode="r",encoding="utf-8")
s = f.read()
print(s)
f.close()
结果:
2 . read(n)读取N个字符,需注意的是.如果再次读取,那么会在当前位置继续去读而不是从头读,如果使用的是 rb 模式,则读取出口的是 n 个字节
f = open("../drift.txt", mode="r", encoding="utf-8") # mode 为r
s = f.read(3)
print(s)
f.close()
结果:
f = open("drift", mode="rb") # mode 为 rb
s = f.read(3)
print(s)
f.close()
结果:
3 . readline() 一次读取一行的数据,注意:readline()结尾,每次读取出来的数据都会有一个\n 所以呢,需要我们使用strip()方法来去掉\n或者空格
f = open("../drift.txt", mode="r", encoding="utf-8")
s = f.readline()
s1 = f.readline()
s2 = f.readline()
print(s)
print(s1)
print(s2)
f.close()
结果:
4. readlines() 将每一行形成一个元素,放到一个列表中,将所有的内容都读取出来,文件过大容易出现内存崩溃的问题,不推荐使用.
f = open("drift", mode="r", encoding="utf-8")
lst = f.readlines()
for line in lst :
print(line.strip())
f.close()
结果:
5. 循环读取: 这种方式是最好的,每次读取一行内容,不会产生内存溢出的问题,推荐使用.
f = open("../drift.txt", mode="r", encoding="utf-8")
for line in f :
print(line.strip())
f.close()
写模式(w , wb)
写文件的时候注意,如果没有文件,则会创建,如果文件存在,则会将原文件的内容删除,再写入新的内容
f = open("drift", mode="w", encoding="utf-8")
f.write("你是谁")
f.flush() # 刷新,每次写完文件切记刷新,良好的习惯.
f.close()
尝试读一读刚才写入的文件
f = open("drift", mode="r", encoding="utf-8")
s = f.read()
print(s)
f.close()
结果如下:
wb 模式下.可以不指定打开文件的编码,但是在写文件的时间必须捋字符串转化成为utf-8的bytes数据.如下:
f = open("drift", mode="wb")
f.write("你是谁,我在那".encode("utf-8"))
f.flush()
f.close()
结果如下 :
追加(a,ab)
在追加模式,我们写入的内容会追加在文件的结尾(会在光标的后面添加) . 如下 :
f = open("drift", mode ="a",encoding="utf-8")
f.write("我是你的什么,请你回答我")
f.flush()
f.close()
结果:
ab 模式:
f = open("drift", mode="ab")
f.write("你问我我是谁我在哪".encode("utf-8"))
f.flush()
f.close()
结果 :
读写模式(r+ ,r+b):
对于读写模式,必须是先读,因为默认光标是在开头的,准备读取的,当读完了之后在进行写入,我们以后使用的频率最高的模式就是r+
正确的操作:
f = open("drift", mode="r+",encoding="utf-8")
s = f.read()
f.write("你是谁的谁,我是我的我")
print(s)
f.flush()
f.close()
运行结果:
drift 文件中:
错误的操作:
f = open("drift", mode="r+",encoding="utf-8")
f.write("你是谁的谁,我是我的我")
s = f.read()
print(s)
f.flush()
f.close()
运行结果:
drift 文件中:
** 将开头的内容写成了"你是谁的谁,我是我的我" 然后读取的数据才是文件中的内容
所以记住: 在r+ 模式中,必须是先读取,然后再写入
写读(w+.w+b)
先讲所有的内容先清空,然后再写入,最后读取,但是读取的内容是空的,不常用
f = open("drift",mode="w+",encoding="utf-8")
f.write("难搞哦")
s = f.read()
print(s)
f.flush()
f.close()
结果如下 :
有人会说,先读不就好了么,错,W+模式下,一开始读取不到数据,然后写的时候再捋原来的内容清空,所以,很少用.
追加读(a+):
a+ 模式下,不论先读还是后读,都是读取不到数据的.
f = open("drift",mode="w+",encoding="utf-8")
f.write("难搞哦")
s = f.read()
print(s)
f.flush()
f.close()
还有一些其他的带b 的操作,就不再多描述了哈,就是把字符换成字节,仅此而已
其他相关操作
seek
seek(n)光标移动到n位置,注意,移动的单位是byte,所以如果不是utf-8的中文部分要是 3 的倍数
通常我们使用seek()都是来移动到开头或者结尾
移动到开头 : seek(0)
移动到当前光标所在位置: seek(0,1)
移动到结尾: seek(0,2)
seek 的第二个参数表示的是从哪个位置进行偏移,默认是0 , 表示开头,1 表示当前位置, 2表示结尾.
f = open("drift",mode="r+",encoding="utf-8")
f.seek(0) # 移动光标到开头
s = f.read() # 读取内容
print("内容是",s)
f.seek(0) # 再次将光标移动到开头
f.seek(0,2) # 将光标移动到结尾
s1 = f.read() # 读取内容
print("内容是",s1)
f.seek(3) # 移动光标 到第一个字符后,
f.write("那是一个冬天 ,没有你的存在的身影") #会将后面的删除掉
f.seek(0)
s2 = f.read()
print("内容是",s2)
f.close()
结果如下:
tell()
使用tell()可以帮助我们获取到当前光标在什么位置
f = open("drift",mode="r+",encoding="utf-8")
f.seek(0) # 光标在开头
s = f.read() # 读取内容,此时移动到结尾
print("内容是:",s)
f.seek(0) # 在次将光标移动到开头
f.seek(0,2) # 将光标移动到结尾
s1 = f.read() # 读取内容, 什么都没有为空
print("内容是:",s1)
f.seek(0) # 移动到开头
f.write("我是谁,我在哪") # 写入信息
print(f.tell()) # 当前光标所在位置
f.flush()
f.seek(0) # 再次移动到开头
s2 = f.read()
print(s2)
f.close()
结果如下:
truncate() 截断文件
with open("drift",mode="w",encoding="utf-8") as f :
f.write("每天都是一个新的开始") # 写入字符
f.seek(3) # 光标移动到3 也就是第一个字符后,
f.truncate() # 删除光标后面的所有内容
print(open("drift",mode="r",encoding="utf-8").read()) # 读取删除之后的文件
结果 :
定义函数的表达:
def read_text(filename, text):
with open(filename, mode="w", encoding="utf-8") as f:
f.write(text) # 写入字符
f.seek(3) # 光标移动到3 也就是第一个字符后,
f.truncate() # 删除光标后面的所有内容
return open(filename, mode="r", encoding="utf-8").read()
a = read_text(filename='drift.txt', text='每天都是一个新的开始')
结果同上
with open("drift",mode="r+",encoding="utf-8") as f :
s = f.read() # 读取当前文件内容
print(s)
f.seek(3) # 光标移动到3 也就是第一个字符后,
f.truncate() # 删除光标后面的所有内容
print(open("drift",mode="r+",encoding="utf-8").read()) # 读取删除之后的文件内容
结果显示 :
注意 : 深坑请注意,在 r+ 模式下,如果读取了内容,不论读取内容多少,光标显示的是多少,再写入或者操作文件的时候都是在结尾进行的操作.
所以 ,如果想做截断操作,记住了,要先挪动光标到你想要截取的位置,然后再进行截断关于truncate(n),如何给出了n, 则从开头进行截断,如果不给n,则从当前位置截取,后面的内容都会别删除
修改文件内容以及另一种打开文件的方式
文件修改,只能将文件的内容读取到内存中,将信息修改完毕,然后将源文件删除,将新的文件的名字改为老文件的名字.
import os
with open("drift",mode="r",encoding="utf-8") as f1, \
open("drift_new",mode="w",encoding="utf-8") as f2:
s = f1.read()
new_s = s.replace("每一天都是新的开始","谁是谁的谁") # 修改的内容
f2.write(new_s)
os.remove("drift") # 删除源文件
os.rename("drift_new","drift") # 重新命名
运行以上代码就会把原文件内容"每一天都是新的开始" 替换成为 “谁是谁的谁”
弊端 : 一次将所有的内容进行读取,内存溢出,解决方案: 一行行的进行读取和替换.
就需要引入 os 模块来实现
import os
with open("drift",mode="r",encoding="utf-8") as f1, \
open("drift_new",mode="w",encoding="utf-8") as f2:
for line in f1:
new_line = line.replace("我喜欢明天的明天","谁是谁的谁") # 替换文件中的内容
f2.write(new_line) # 写入新的内容
os.remove("drift") # 删除源文件
os.rename("drift_new","drift") # 重新命名
运行以上代码,就会一行行找出来需要替换的内容后,再来操作修改.推荐使用