>[success] # Python -- 文件的读写 ~~~ 1.一个运行中的程序会存取放在随机存取存储器(RAM)上的数据。RAM 读 取速度快,但 价格昂贵,需要持续供电,断电后保存在上面的数据会自动消 失。磁盘速度比 RAM 慢, 但容量大、费用低廉并且多次插拔电源线仍可保 持数据。因此,计算机系统在数据存储设 计中做出很大的努力来权衡磁盘和 RAM。程序员需要在非易失性介质(例如磁盘)上做 持久化存储和检索数 据。 2.因此整个读写操作相当于是在ram 执行的,使用的是ram内存条中的内存, 通俗的说是在一个文件 名下的字节流,把数据从一个文件读入内存,然后从 内存写入文件。 ~~~ >[danger] ##### 常见的读写模式 ~~~ 1.了解读写的文件分两种,一种是普通文本文件,一种是二进制文件(图片, 音乐等),因此在python中,也分这两种模式,t(或者省略)代表文本类 型; b 代表二进制文件。 2. 只读(r, rb) 3. 只写(w, wb) 4. 追加(a, ab) 5. r+读写 6. w+写读 7. a+写读(追加写读) ~~~ >[danger] ##### 使用open -- 进行读写操作 ~~~ 1.open(filename,mode,encoding)中常用的三个参数 ,第一个filename是文件 名称,mode使用的读写模式,encoding 进行编码解码 2.在操作文件读写后需要关闭句柄,也就是close 操作 ~~~ >[danger] ##### read -- (r,rb) 只读模式 ~~~ 1.r是rt 模式的缩写,是读取文本类的,rb是读取二进制类的例如图片 2.使用 read() 函数一次读入文件的所有内容。但在 读入文件时要格外注意, 1GB 的文件会用到相同大小的内存。因此会有更好的优化方案见案例 3.rb读取出来的数据是bytes类型, 在rb模式下. 不能选择encoding字符集. 4.read(n) 读取n个字符. 需要注意的是. 如果再次读取. 那么会在当前位置继 续去读⽽而不 是从头读, 如果使⽤用的是rb模式. 则读取出来的是n个字节 ~~~ * 案例 普通的读写案例 ~~~ f = open('../file/test', 'r', encoding='utf-8') s = f.read() #read 是当前对象的一个方法,读出这个对象内的内容 print(s) ~~~ * 优化 读多少拿多少 ~~~ f = open('../file/test', 'r', encoding='utf-8') content = '' # 记录所有内容 chunk = 50 # 一次读取多少个字符 while True: s = f.read(chunk) if not s: break content += s print(content) ~~~ >[danger] ##### write -- (w, wb) 写模式存在则删除 ~~~ 1.写的时候注意. 如果没有⽂文件. 则会创建⽂文件, 如果⽂文件存在. 则将原 件中原来的内容删除, 再 写入新内容 2.在写的时候注意两个好习惯一个是刷新,一个是关闭 f.flush() /f.close() 3.这是只写模式,不能进行读的操作 ~~~ * 写入案例 -- write篇章 ~~~ content = '写入的新的内容' f = open('../file/test', 'w', encoding='utf-8') f.write(content) f.flush() f.close() ~~~ * 写入案例 -- 万能print ~~~ # print 因为自带换行符,因此在使用的时候要考虑去掉默认的换行符 content = '写入的新的内容' f = open('../file/test', 'w', encoding='utf-8') print(content, file=f, sep='', end='') f.close() ~~~ * 优化 写多少存多少 ~~~ content = '写入的新的内容' offset = 0 chunk = 2 # 一次写入多少 f = open('../file/test', 'w', encoding='utf-8') while len(content) > offset: f.write(content[offset:offset+chunk]) offset += chunk f.close() ~~~ * 二进制写入 wb模式下. 可以不指定打开⽂文件的编码. 但是在写⽂文件的时候必须将字符串串转化成utf-8的 bytes数据 ~~~ f = open("⼩小娃娃", mode="wb") f.write("⾦金金⽑毛狮王".encode("utf-8")) f.flush() f.close() ~~~ >[danger] ##### 追加(a, ab) -- 在末尾追加 ~~~ 1.在追加模式下. 我们写入的内容会追加在⽂文件的结尾,必须文件存在 ~~~ * 案例 ~~~ f = open('../file/test', 'a', encoding='utf-8') f.write("追加内容") f.flush() f.close() ~~~ >[danger] ##### r+ /r+b -- 读写模式 ~~~ 1.对于读写模式. 必须是先读. 因为默认光标是在开头的. 准备读取的. 当读完 了之后再进⾏行行 写入. 使⽤频率最⾼高的模式就是r+ 2..在没有任何操作之前进行写. 在开头写 3. 如果读取了一些内容. 再写, 写入的是最后,也就是说read(1)执行了虽然 是读一个字符,但追加的内容也会在整个文章最后 ~~~ * 必须是先读取. 然后再写入 ~~~ f = open("⼩小娃娃", mode="r+", encoding="utf-8") content = f.read() f.write("麻花藤的最爱") print(content) f.flush() f.close() ~~~ * 如果先写后读就会出现,追加的内容在,开头而不是在结尾,错误示范如下: ~~~ f = open("⼩小娃娃", mode="r+", encoding="utf-8") f.write("哈哈") content = f.read() print(content) f.flush() f.close() 结果: 将开头的内容改写成了了"哈哈", 然后读取的内容是后⾯面的内容. ~~~ >[danger] ##### readline() / readlines() -- 以行为单位读 ~~~ 1.readline() 和 .readlines() 之间的差异是后者一次读取整个文件 2.readline() 每次只读取一行,通常比 .readlines() 慢得多。仅当没有足够内存可以一次读取整个文件时,才应该使用 .readline()。 ~~~ * 案例 -- 直接常用写法 ~~~ f = open("吃的", mode="r", encoding="utf-8") for line in f: # 每次读取一行. 赋值给前面的line变量 print(line) f.close() ~~~ * 性能 读法 ~~~ poem = '' fin = open('relativity', 'rt' ) while True: line = fin.readline() if not line: break poem += line fin.close() ~~~ >[danger] ##### w+/w+b -- 写读 ~~~ 1. 先将所有的内容清空. 然后写入. 最后读取. 但是读取的内容是空的, 不常⽤ 2. 一开始读取不到数据. 然后写的时候再将原来的内容清空,不常用 ~~~ * 案例 ~~~ f = open("⼩小娃娃", mode="w+", encoding="utf-8") f.write("哈哈") content = f.read() print(content) f.flush() f.close() ~~~ >[danger] ##### 追加读(a+) ~~~ 1.啥用没有,a+模式下, 不论先读还是后读. 都是读取不到数据的. ~~~ ~~~ f = open('../file/test', 'a+', encoding='utf-8') f.write("追加内容") s = f.read() print(s) ~~~ >[danger] ##### seek(n) -- 光标移动 ~~~ 1. seek(n) 光标移动到n位置, 注意, 移动的单位是byte. 所以如果是UTF-8的 中⽂文部分要 是3的倍数. 三个字节构成一个字符 2. 移动到开头: 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() ~~~ >[danger] ##### 使用with自动关闭文件 ~~~ 1.如果你忘记关闭已经打开的一个文件, 在该文件对象不再被引用之后 Python 会关掉此文 件。这也就意味着在一个函数中打开文件,没有及时关 闭它,但是在函数结束时会被关 掉。然而你可能会在一直运行中的函数或 者程序的主要部分打开一个文件,应该强制剩下 的所有写操作完成后再关 闭文件。 Python 的上下文管理器(context manager)会清理一些资源,例如打开的文件。它的形式 为 with expression as variable: with open('relativity', 'wt') as fout: ... fout.write(poem) ... 完成上下文管理器的代码后,文件会被自动关闭。 ~~~ >[danger] ##### 修改文件内容 * 先读在写写的文件,删除读的,重命名写的 ~~~ import os with open("吃的", mode="r", encoding="utf-8") as f1, \ open("吃的_副本", mode="w", encoding="utf-8") as f2: for line in f1: s = line.replace("菜", "肉") f2.write(s) os.remove("吃的") # 删除文件 os.rename("吃的_副本", "吃的") # 重命名文件 ~~~ >[danger] ##### 整合模式 ~~~ 1.使用with 2.使用for 循环 ~~~