多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
[TOC] ## **文件读写模式概述** ### `r` 读文件模式 * r 只读模式 普通读模式,不能写入,不指定编码的话默认使用utf-8编码读取文件 * r+ 读写模式 可以写入,但默认只能将新内容写到文件最后面,可以理解为追加 * rb 二进制读模式 数据读到内存里直接是bytes格式,主要针对图片,视屏等无编码文件 ### `w` 写文件模式 * w 只写模式 只能写不能读,且是新创建文件来写,如果指定的文件存在,文件内容会先被清空 * w+ 写读模式 能写能读,也是新创建文件来写,且只能读新写入的内容,没什么用 * wb 二进制写模式 二进制写模式,不能读,新建文件来写,存在的话会先清空 ### `a` 追加模式 * a 追加模式 只能往文件中追加内容,不能读也不能写 * ab 二进制追加模式 写入时需要直接传入以某种编码的0100101,即:字节类型 ## **`r`模式详解** ### r 只读模式 * 语法案例 ``` f = open(file='D:/dir/file.txt',mode='r',encoding='utf-8') data = f.read() f.close() ``` * 语法解释: ``` file='D:/dir/file.txt' 文件路径 mode='r' 模式=只读 encoding='utf-8' 该文档使用的编码 f.read() 读取所有内容,内容是已经转换完毕的字符串。 f.close() 表示关闭文件 ``` >PS: 此处的encoding必须和文件在保存时设置的编码一致,不然会造成乱码。 file、mode、encoding关键字都可以省略,如`('file.txt','r','utf-8')` ### r+ 读写模式 * 语法案例 ``` f = open("test.txt",'r+',encoding="utf-8") data = f.read() #读内容 print(data) f.write("\ngirl 河北") #写内容 f.close() ``` >上面的内容写到哪个位置了呢?答案是追加到了最后面。 ### rb 二进制读模式 * 语法案例 ``` f = open(file='D:/firedir/test.txt',mode='rb') data = f.read() f.close() ``` * 语法解释: ``` file='D:/firedir/test.txt' 文件路径 mode='rb' 只读(可以修改为其他) f.read() 读取所有内容 f.close() 关闭文件 ``` > 二进制读模式打开文件时并未指定encoding,是因为直接以rb模式打开了文件 ,数据读到内存里直接是bytes格式,如果想看内容,还需要手动decode,所有在文件打开阶段,不需要指定编码 ### chardet 获取文件编码 当一个要处理的文件不知道编码,却要打开这个文件,可以用这个方法获取文件的编码 ``` import chardet f = open('log',mode='rb') data = f.read() f.close() result = chardet.detect(open('log',mode='rb').read()) print(result) 输出: {'encoding': 'GB2312', 'confidence': 0.99, 'language': 'Chinese'} ``` ## **`w` 模式详解** ### w 只写模式 * 语法案例 ``` f = open(file='D:/firedir/test.txt',mode='w',encoding='utf-8') f.write('北大,微信号:xxxxx') f.close() ``` * 语法解释: ``` file='D:/firedir/test.txt' 表示文件路径 mode='w' 表示只写 encoding='utf-8' 将要写入的unicode字符串编码成utf-8格式 f.write(...) 表示写入内容 f.close() ``` ### wb 二进制写模式 * 语法案例 ``` f = open(file='D:/firedir/test.txt',mode='wb') f.write(b'm\xe7\xbd\x97') f.write('n钢'.encode('utf-8')) f.close() ``` * 语法解释: ``` file='D:/firedir/test.txt' 文件路径 mode='wb' 只以2进制模式写 f.write(b'm\xe7\xbd\x97') 写入字节内容(utf8编码的`m罗`) f.write('n钢'.encode('utf-8')) 写入普通内容并指定转码为utf8 f.close() ``` >注意:wb,写入时指定编码方式的二进制内容,或当场用encode方法转码 ### w+ 写读模式 * 语法案例 ``` f = open("test.txt",'w+',encoding="utf-8") print('--1',f.read(),'1--') f.write("哈哈") print("--2",f.read(),"2--") f.seek(0) print("--3",f.read(),"3--") f.close() ``` * 输出和解释 ``` --1 1-- --2 2-- --3 哈哈 3-- ``` >注意第一行两个标记1中间是空的,代表根本没读到内容,因为先清空了文件 第二行的标记之间也是空的,因为写入数据后,光标指向了最后, 第三行重新指定了光标,才能读出来东西,这功能没什么用 ## **`a` 追加模式详解** ### a 追加模式 * 语法案例 ``` f = open("test.txt",'a',encoding="utf-8") f.write("\n杜姗 京") f.close() ``` * 运行结果 ``` 姓名 地区 杜姗 京 ``` >注意: 文件操作时,以 “a”或“ab” 模式打开,则只能追加,即:在原来内容的尾部追加内容 ### ab 二进制追加 * 语法案例 ``` f = open("test.txt",'ab') f.write(b'm\xe7\xbd\x97') f.write('n钢'.encode('utf-8')) f.close() ``` * 语法解释: ``` mode='ab' 只以2进制模式追加 f.write(b'm\xe7\xbd\x97') 写入字节内容(utf8编码的`m罗`) f.write('n钢'.encode('utf-8')) 写入普通内容并指定转码为utf8 f.close() ``` >注意:wb,写入时指定编码方式的二进制内容,或当场用encode方法转码 ## **其它方法简述** ### fileno 返回文件句柄索引 `fileno(self, *args, **kwargs)` 返回文件句柄在内核中的索引值,以后做IO多路复用时可以用到 ### flush 强制刷写至磁盘 `flush(self, *args, **kwargs)` 把文件从内存buffer里强制刷新到硬盘 ### readable 是否可读 `readable(self, *args, **kwargs)` 判断是否可读,可读为True,linux中,一切皆文件,但如设备类文件就不可读 ### readline 读一行 `readline(self, *args, **kwargs)` 只读一行,遇到\r or \n为止 ### seek 移动光标 `seek(self, *args, **kwargs)` 把操作文件的光标移到指定位置 **注意:** seek的长度是按字节算的, 字符编码存每个字符所占的字节长度不一样。 如“路飞学城” 用gbk存是2个字节一个字,用utf-8就是3个字节,因此以gbk打开时,seek(4) 就把光标切换到了“飞”和“学”两个字中间。 但如果是utf8,seek(4)会导致,拿到了飞这个字的一部分字节,打印的话会报错,因为处理剩下的文本时发现用utf8处理不了了,因为编码对不上了。少了一个字节 ### seekable 是否可以移动光标 `seekable(self, *args, **kwargs)` 判断文件是否可进行seek操作 ### tell 返回光标位置 `tell(self, *args, **kwargs)` 返回当前文件操作光标位置 ### truncate 截断文件 `truncate(self, *args, **kwargs)` 按指定长度截断文件 指定长度的话,就从文件开头开始截断指定长度,不指定长度的话,就从当前位置到文件尾部的内容全去掉。 ### writable 判断是否可写 `writable(self, *args, **kwargs)` 判断文件是否可写 ## **循环读取一行** ### 用for循环 ``` f = open("test.txt",'r',encoding="utf-8") for line in f: print(line) f.close() ``` ### 用readline ``` f = open("test.txt",'r',encoding="utf-8") print(f.readline()) print(f.readline()) f.close() ``` ## **如何修改文件** ### 硬盘的存储原理 当你把文件存到硬盘上,就在硬盘上划了一块空间,存数据,等你下次打开这个文件 ,seek到一个位置,每改一个字,就是把原来的覆盖掉,如果要插入,是不可能的,因为后面的数据在硬盘上不会整体向后移。所以就出现你想插入,却变成了会把旧内容覆盖掉。 如果要修改,就有两种方法: 1. 占内存方法 把内容全部读到内存里,数据在内存里可以随便增删改查,修改之后,把内容再全部写回硬盘,把原来的数据全部覆盖掉,但如果文件很大,可能会把内存撑爆 2. 占硬盘方法 如果不想占内存,只能边读边改,就是打开旧文件的同时,生成一个新文件,边从旧的里面一行行的读,边往新的一行行写,遇到需要修改就改了再写到新文件 ,这样内存里一直只存一行内容。改完后,再把旧的覆盖掉,但在改的过程中,还是有2份数据。 ### 案例: 修改黄鹤楼这首诗的第三行为'哈哈哈',文件名为`my.txt`,诗如下: ``` 昔人已乘黄鹤去,此地空余黄鹤楼。 黄鹤一去不复返,白云千载空悠悠。 晴川历历汉阳树,芳草萋萋鹦鹉洲。 日暮乡关何处是?烟波江上使人愁。 ``` #### 占硬盘方式代码示例 ```python import os f_name = "my.txt" f_new_name = "%s.new" % f_name old_str = "晴川历历汉阳树,芳草萋萋鹦鹉洲" new_str = "哈哈哈" f = open(f_name,'r',encoding="utf-8") f_new = open(f_new_name,'w',encoding="utf-8") for line in f: if old_str in line: new_line = line.replace(old_str,new_str) else: new_line = line f_new.write(new_line) f.close() f_new.close() os.rename(f_new_name,f_name) #把新文件名字改成原文件的名字,,windows使用os.replace ``` #### 占内存方式代码示例1 这种方法用字符串替换方式实现 ```python f_name = "my.txt" old_str = "晴川历历汉阳树,芳草萋萋鹦鹉洲" new_str = "哈哈哈" f = open(f_name,'r+',encoding="utf-8") data=f.read() data=data.replace(old_str,new_str) f.seek(0) f.truncate() f.write(data) f.close() ``` #### 占内存方式代码示例2 这种方法用for循环加readlines实现,可以模糊匹配让后整行替换 ```python f_name = "my.txt" old_str = "晴川历历汉阳树,芳草萋萋鹦鹉洲" new_str = "哈哈哈" f = open(f_name,'r+',encoding="utf-8") data=f i=0 for line in data.readlines(): if i ==0: f.seek(0) f.truncate() i+=1 if old_srt in line: line=new_srt f.write(line) print(f.tell()) f.close() ```