python基础 | 文件操作详解
一、文件操作初识
f = open('文件路径', '编码方式', '操作方式') # 注意里面所有内容,需加引号 ”
打开一个文件需要知道的内容有:
文件路径:c:\文件.txt(绝对路径和相对路径)
编码方式:utf-8、gbk、GB2312…(windows 默认的编码方式gbk,linux默认的编码方式为utf-8)
操作方式:只读、只写、写读、读写、追加等
例如:打开一个已经存在的文件
f = open('c:\python\文件.txt',encoding='utf-8',mode='r') content = f.read() print(content) f.close()
执行输出:今天天气真好
代码解释:
f变量:可以命令为f_obj,file,f_handler... 这个变量,称之为文件句柄(句柄是操作系统在生成对象时分配给对象的唯一标识)
open命令:其实就是调用系统打开文件的动作。
f.close() : 关闭文件
操作文件流程:打开一个文件,产生一个文件句柄,对文件句柄进行操作,关闭文件
打开文件时的报错原因:
1、UnicodeDecodeError:编码不一致,存储文件编码与打开文件时的编码方式不同
2、FileNotFoundError或[Error 22] Invalid argument: '\u202adD:\\xx.txt':路径问题(文件名错误)
解决方式:
1.将每个\变成 \\,比如 D:\\xx.txt
2.前面加r ,比如 r'D:\xx.txt'
二、文件的读、写、追加
1、文件的读:
r *****
rb ***
r+ *****
r+b
(1) r:对于r模式,mode可以不写
f=open('c:\python\文件',encoding='utf-8',mode='r') content=f.read() print(content) f.close()
(2) rb:文件以字节(8bit,16进制)进行读取。不需要编码方式。主要用于非文字类的文件读取。
f=open('c:\python\图片.jpg',mode='rb') print(f.read()) f.close 输出结果是:b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x0…….
(3) r+:读写,先读后追加。
r+ 一定要先读后写,否则会错乱或者读取不到内容
先读后写:在文件后追加上写的内容
path='c:\python\文件.txt' f=open(path,encoding='utf-8',mode='r+') content=f.read() #先读 print(content) f.write('天安门') #后追加 f.close()
不读直接写:写的内容会从文件开始覆盖原文件(按照每个不同字符的字节的大小)
path='c:\python\文件.txt' f=open(path,encoding='utf-8',mode='r+') f.write('天安门') f.close()
先写后读,不可取
f = open('log.txt',encoding='utf-8',mode='r+') f.write('BBB') content = f.read() print(content) f.close()
执行输出,内容是空的。为什么呢?因为光标,默认是从0开始。只要进行一个动作,光标就会移动,包括读取。上面的代码写入时,光标移动到最后了。所以执行f.read()时,读取不到后面的内容了。
(4)r+b:文件以字节形式进行先读后以字节形式写,没有encoding。
path='c:\python\文件.txt' f=open(path,mode='r+b') print(f.read()) f.write(b'\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8')
2、文件的写
w
wb
w+
w+b
(1)w:没有文件,创建文件;有文件,文件先清空,后写入
f=open('文件',encoding='utf-8',mode='w') #在相对路径下先创建这个文件 f.write('你好,我是summer') f.close()
(2)wb:以bytes写入,写入的内容,必须要转换为bytes类型才可以
f=open('文件',mode='wb') f.write(b'\xe5\xa4\xa9\xe5\xae\x89\xe9\x97\xa8') f = open('log.txt',mode='wb') f.write('人生苦短,我想学Python'.encode(encoding="utf-8")) f.close()
(3)w+:写读,先写后读,但是此时光标已经移至最后,读出的内容可能只有一个换行符。但是可以通过改变光标位置进行读操作
f = open('log.txt',encoding='utf-8',mode='w+') f.write('AAA') print(f.tell()) #按直接去读光标位置 f.seek(0) #调整光标位置 content = f.read() print(content) f.close() 执行输出: 3 AAA
ftp的断点续传,需要用到光标,一定会用到tell和seek
(4)w+b:以字节方式写入加读取
3、文件的追加
a
ab
a+
a+b
a:没有文件,创建文件追加;有文件,在文件后面追加
f=open('文件追加',encoding='utf-8',mode='a') f.seek(1) #不管光标在哪里,都是在最后追加 f.write('123')
三、文件的改
文件的改(需要用到python的内置函数 os)
1、以读的模式打开原文件,产生一个文件句柄f1;
2、以写的模式创建一个新的文件,产生一个文件句柄f2;
3、读取原文件的内容,进行修改,并将修改后的写入到新文件中;
4、将原文件删除;
5、将新文件重新命名为原文件
方法一
import os with open('maitian.csv',encoding='utf-8',mode='r')as f1,\ open('maitian2.csv',encoding='utf-8',mode='w')as f2: old_content=f1.read() new_content=old_content.replace('标题','biaoti') f2.write(new_content) os.remove('maitian.csv') os.rename('maitian2.csv','maitian.csv')
方法二
import os with open('maitian.csv',encoding='utf-8',mode='r')as f1,\ open('maitian2.csv',encoding='utf-8',mode='w')as f2: for line in f1: new_line=line.replace('biaoti','标题') f2.write(new_line) os.remove('maitian.csv') os.rename('maitian2.csv','maitian.csv')
四、文件读取的五种方式
r模式有5种模式读取
第一种:全部读取出来 f.read()。全部读取,对于较大的文件,内存会负担不起
f = open('天气.txt',encoding='utf-8') content = f.read() print(content) f.close()
第二种:一行一行的读 f.readline()。按行读取,但是中间会有个换行符,这是因为每行文件末尾默认都有一个换行符
f = open('天气.txt',encoding='utf-8') print(f.readline()) print(f.readline()) print(f.readline()) f.close()
第三种:f.readlines() 按行读取,返回一个列表,列表中的每个元素就是每一行的字符串
f = open('天气.txt',encoding='utf-8') print(f.readlines()) f.close()
执行输出:
['03月27日(今天)\n', '晴转多云\n', '11~27℃\n', '西南风 1级\n', '重度污染']
第四种:读取一部分f.read(n)。在r模式下,read(n) 按照字符去读取。rb模式下按照字符的bytes模式读取
f = open('天气.txt',encoding='utf-8') print(f.read(3)) f.close()
执行输出:
03月 # 表示3个字符
第五种:for循环读取
f = open('天气.txt',encoding='utf-8') for line in f: print(i.strip()) f.close()
执行输出:
03月27日(今天)
晴转多云
11~27℃
西南风 1级
重度污染
在for循环中,每次读取一行,结束之后,内存就释放了。所以在整个for循环个过程中,始终只占用了一行内容的内存。推荐使用第5种方式。
五、文件的常用操作方法
- read():文件的读操作
- write():文件的写操作
- close():文件关闭
- seek():移动光标位置,在w+或者a+的时候可以通过移动光标的位置进行读取,光标是按照字节来移动
- seek(0,2):将光标移到最后一位
- tell():返回光标的位置
- readable():判断是否可读
- writable():判断是否可写
f = open('log.txt',encoding='utf-8',mode='r+') print(f.writable()) f.close()
执行输出:True
f.truncate()
在writable模式下进行截取文件,所以文件的打开方式必须可写r+、a+,不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
f = open('log.txt',encoding='utf-8',mode='r+') # 截取3个字节 f.truncate(3) content = f.read() print(content) f.close()
执行输出:中
f = open("E:\PyCharm\\test.txt",mode ="w",encoding = "utf-8") f.write("哈哈") # 写入两个字符 f.seek(3) # 光标移动到3,就是两个字的中间 f.truncate() # 删除光标后面的所有内容 f.close() # 关闭 f = open("E:\PyCharm\\test.txt",mode ="r+",encoding = "utf-8") du = f.read(3) # 读取12个字节,意思就是三个字 f.seek(4) print(f.tell()) f.truncate() # 删掉后面的所有内容 f.flush() # 刷新 f.close() # 关闭
注意:在r+模式下,如果读取内容,不论读取内容多少,光标显示的是多少,再次写入或者操作文件的的时候都是在结尾进行的操作,所以如果想做截取操作,记住了,先要挪动光标,挪动到你想要截取的位置,然后再进行截取关于truncate(n),如果给出了n,则从开头进行截取,如果不给n,则从当前位置截取,后面的内容将会被删除。
f.seek()
改变当前文件指针的位置
f.seek(offset,from_what)
- from_what的值,从哪个位置进行偏移,如果是0表示开头,如果是1表示当前位置,2表示文件的结尾。默认为0,即文件开头。
- 移动到开头:seek(0) ;
- 移动到结尾:seek(0,2) ;
- seek(x,0):从文件首行首字符开始移动x个字符
- seek(x,1):从当前为往后移动x个字符
- seek(-x,2):从文件的结尾往前移动x个字符
注意,移动的单位是byte(字节),所以如果是UTF-8的中文部分要3的倍数,意思就是一个字要三个字节
f = open("E:\PyCharm\\test.txt",mode ="r+",encoding = "utf-8") f.seek(0) #光标移动开头 du = f.read() #读取内容此时光标移动到结尾 print(du) f.seek(0) #再次将光标移动到开头 f.seek(0,2) #将光标移动到结尾 du1 = f.read() #读取内容什么也没有读到因为此时光标在后面 print(du1) f.seek(0) #光标移动到开头 f.write("哈哈哈") #写入信息,此时光标在9,因为中文3个字节代表一个字符3*3=9 f.flush() #刷新 f.close() #关闭
f.tell()
使用tell()可以帮我们获取到当前光标在什么位置
f = open("E:\PyCharm\\test.txt",mode ="r+",encoding = "utf-8") f.seek(0) # 光标移动到开头 f.write("哈哈哈") # 写入信息,此时光标在9,因为中文3个字节代表一个字符3*3=9 print(f.tell()) # 此时获取光标所在的位置,中文一个字三个光标为一个字,因为中文3个字节代表一个字符 f.flush() # 刷新 f.close() # 关闭
六、主动关闭文件句柄的方法
有的时候会忘记在末尾加上f.close(),所以有主动关闭文件句柄的方法,这种方法会在一定时间内关闭,有利有弊,为了避免忘记回收文件句柄,需要使用with open方法,代码执行完毕之后,自动关闭文件句柄
功能1:自动关闭文件句柄
with open('log.txt',encoding='utf-8') as f: print(f.read())
功能2:一次性操作多个文件
with open('文件',encoding='utf-8',mode='r') as f1,\ open('文件1',encoding='utf-8',mode='w') as f2: print(f1.read()) f2.write('qwert')
有些情况下,必须先关闭,才能执行某动作的情况下,不能用with,这种情况比较少见。
所有的文件,不是直接在原文件修改的。它是进行了5步操作:
1.将原文件读取到内存。
2.在内存中进行修改,形成新的内容。
3.将新的字符串写入新文件。
4.将原文件删除。
5.将新文件重命名成原文件。
题目:将log文件内容中含有summer的,替换为spring
import os with open('log',encoding='utf-8') as f1,\ open('log.bak',encoding='utf-8',mode='w') as f2: content = f1.read() new_content = content.replace('summer','spring') f2.write(new_content) os.remove('log') os.rename('log.bak','log')
这种方法,不好。如果文件比较大,内存直接爆掉。因为f1.read()是将文件所有内容写入内存中。
推荐做法:
import os with open('log',encoding='utf-8',mode='r') as f1,\ open('log.bak',encoding='utf-8',mode='w') as f2: for i in f1: new_i = i.replace('summer', 'spring') f2.write(new_i) os.remove('log') os.rename('log.bak','log')
这种方式,每次只占用一行。所有软件,都是执行这5步的。
不同模式打开文件的列表:
- r:以只读的方式打开文件,文件的指针将会放在文件的开头,为默认模式
- rb:以二进制格式打开一个文件用于只读,文件指针会在文件的开头
- r+:打开一个文件用于读写,文件指针将会在文件的开头
- rb+:以二进制格式打开一个文件用于读写,文件指针会放在文件的开头
- w:打开一个文件用于写入,如果该文件已存在则将会覆盖文件,如果不存在则创建新文件
- wb:以二进制打开一个文件用于写入
- w+:打开一个文件用于读写
- wb+:以二进制格式打开一个文件用于读写,如果文件存在则覆盖,如果不存在则创建新文件
- a:打开一个文件用于追加内容,如果文件已存在,文件指针会放在文件的结尾,如果不存在则创建新文件进行写入
- ab:以二进制格式打开一个文件用于追加写入
- a+:打开一个文件用于读写,如果该文件已存在,文件指针会放在结尾,文件打开时会是追加模式,该文件不存在则创建新文件
- ab+:以二进制格式打开一个文件用于追加。
Python读取文件忽略文件中空行
读取大量文件时,通常采用readline方法,但如果出现空行情况则需要忽略此时的空行。在网上找了大量代码,发现多数单纯利用strip()方法,但经过实践我发现处理数据时会造成直接不读取空行之后的问题。最后,终于自己学习了相关知识,自己写了一个方法利用isspace()方法,在这留下存档。
def create_car_info(file_name, result_path): with open(file_name, "r", encoding="UTF-8") as r: line = r.readline() while line: #isspace()方法判断当该行是空行时,跳过该行 if line.isspace(): line = r.readline() else: """ 不是空行时,对每一行进行的操作 """ line = r.readline()
如何在Python中一次读取N行文件
从文件中读取数据:信息时代已经到来
with open('src/Step1/test.txt') as file_object: lines = file_object.readlines() for line in lines[:n]: print(line.rstrip())
python读取文件特定的行数
from itertools import islice
file=open("exercise 1.txt") for a in islice(file,1,3): print(a)