python -- 文件操作
一般对文件操作流程如下:
- 打开文件,得打文件句柄并赋值给一个变量;
- 通过句柄对文件进行操作;
- 关闭文件。
文件的基本操作
打开文件 f = open('filename','r',encoding='utf-8') with open('filename',encoding='utf-8') as f
# 一种文件打开的方式,这样的调用模式,文件不会自动关闭
f = open('filename', encoding='utf-8')
# 另一种较为常见的文件打开方式,这样的调用模式,会自动关闭文件
with open('filename', encoding='utf-8') as f_1, \
open('filename2',encoding='utf-8') as f_2:
pass
文件打开的模式分类
模式 | 说明 | 备注 |
---|---|---|
r | 只读模式 | 默认模式 |
w | 只写模式 | 只写,不读 |
a | 追加模式 | 可写,续写,不可读 |
r+ | 读写模式 | 可读,可写,建议使用这种 |
w+ | 写读模式 | 可写,可读,先重建,再读 |
a+ | 追加读写模式 | 类似r+模式 |
rb | 二进制读模式 | |
wb | 二进制读模式 | |
ab | 二进制追加写模式 |
读文件 file.read()
当文件f.read()读取一遍后,文件指针就指向文件的最后一行,如果不将指针返回,是无法读取第二遍。因为f.read()是将文件全读取一遍。
# 一种文件打开的方式,这样的调用模式,文件不会自动关闭
f = open('filename', 'r', encoding='utf-8')
# 另一种较为常见的文件打开方式,这样的调用模式,会自动关闭文件
with open('filename', encoding='utf-8') as f_1:
pass
data = f.read()
# 使用with打开文件,不能再调用read(),因为文件已经关闭
# data_1 = f_1.read()
print(data)
f = open('filename', 'r', encoding='utf-8')
data = f.read()
data_1 = f.read()
print(data)
print('----------这是分割线----------')
print(data_1)
'''
以下是上面程序执行的结果:
The str in the file.
File's name is filename.
----------这是分割线----------
'''
f = open('filename', 'r', encoding='utf-8')
# 只读5个,可以是5个中文,也可以是5个数字或英文
print(f.read(5))
print('--------------------')
# 再只读5个,可以是5个中文,也可以是5个数字或英文,如果是换行符,打印出来也是换行。
print(f.read(5))
写文件 file.write(data)
注意写入内容的格式差异
f = open('filename', 'w', encoding='utf-8')
data = ('''我是第一行。\n我是第二行。\n我是第三行。\n''')
data_1 = ('''
我是第一行。\n
我是第二行。\n
我是第三行。\n
''')
f.write(data)
'''
以下是data传入内容最终效果,最后一行的换行也在内。
我是第一行。
我是第二行。
我是第三行。
'''
f.write(data_1)
'''
以下是data_1传入内容最终效果,最后一行的换行也在内。
我是第一行。
我是第二行。
我是第三行。
'''
追加文件 同写file.write(data),区别是在文件打开的模式上不同,a模式下,同样无法读
f = open('filename', 'a', encoding='utf-8')
data = ('''我是第一行。\n我是第二行。\n我是第三行。\n''')
data_1 = ('''
我是第一行。\n
我是第二行。\n
我是第三行。\n
''')
f.write(data)
'''
以下是data传入内容最终效果,最后一行的换行也在内。
我是第一行。
我是第二行。
我是第三行。
'''
f.write('----------我是分割线----------')
f.write(data_1)
'''
以下是data_1传入内容最终效果,最后一行的换行也在内。
我是第一行。
我是第二行。
我是第三行。
'''
''''
这个文件最终加入的内容效果,最后一行的换行也在内。
我是第一行。
我是第二行。
我是第三行。
----------我是分割线----------
我是第一行。
我是第二行。
我是第三行。
'''
# 在a模式下,同样无法读
f.read()
文件的深入操作
文件读一行 file.readline()
f = open('filename', 'r', encoding='utf-8')
a = f.readline()
b = f.readline()
c = f.readline()
d = f.readline()
print(a, b, c, d)
for i in range(2):
print(f.readline())
'''
以下是打印的效果,包含最后一行换行。有格式上的不同差异。
我是第一行。
我是第二行。
我是第三行。
我是第四行。
我是第五行。
我是第六行。
'''
文件读所有行 file.readlines()
f = open('filename', 'r', encoding='utf-8')
a = f.readlines()
# <class 'list'> ['我是第一行。\n', '我是第二行。\n', '我是第三行。\n', '我是第四行。\n', '我是第五行。\n', '我是第六行。']
print(type(a), a)
for line in a:
print(line)
print('--------------------')
for line_1 in a:
print(line_1.strip())
'''
以下是print(line)和print(line_1)的效果。
由于每一行带换行符号。所以需要用到line.strip()。
我是第一行。
我是第二行。
我是第三行。
我是第四行。
我是第五行。
我是第六行。
--------------------
我是第一行。
我是第二行。
我是第三行。
我是第四行。
我是第五行。
我是第六行。
'''
打印前2行的内容,需要使用循环。即循环打印列表。
f = open('filename', 'r', encoding='utf-8')
a = f.readlines()
for index, line in enumerate(a):
if index == 2:
break
# 这里不用print(line),是因为每一个列表中的元素都含有一个回车符,所以这里用到了strip()
print(line.strip())
'''
以下是以上程序的效果。
我是第一行。
我是第二行。
'''
2层嵌套循环的写法
此时的f已经变成了迭代器
f = open('filename', 'r', encoding='utf-8')
count = 0
exit_flag = 1
while exit_flag == 1:
for line in f:
print(line)
count += 1
if count > 1:
exit_flag = 0
break
1层循环的写法
此时的f已经变成了迭代器
f = open('filename', 'r', encoding='utf-8')
count = 0
for line in f:
if count > 1:
break
print(line)
count += 1
查看文件句柄的指针位置 f.tell()
f = open('filename', 'r', encoding='utf-8')
print(f.tell()) # 0
f.readline()
# 第一句话有多长,那个数值就是这里显示的
print(f.tell())
# 再读5个字符
a = f.read(5)
print(a)
# 返回值是,又加了上面的f.read(5)后的值
print(f.tell())
将文件句柄的指针位置复位 f.seek()
f = open('filename', 'r', encoding='utf-8')
# 先循环打印两行
for i in range(2):
a = f.readline()
print(a.strip())
print(f.tell())
# 0代表文件句柄的起始位,也可以输入你想让它回到的位置
f.seek(0)
# 又打印了第一行的内容
print(f.readline())
查询文件编码 f.encoding
f = open('filename', 'r', encoding='utf-8')
# utf-8
print(f.encoding)
查询文件句柄在内存的编号 f.fileno()
f = open('filename', 'r', encoding='utf-8')
# 一个数字,操作系统专门有一个接口,处理所有文件,这个数字就是所有文件的编号
# 打开的文件并非python打开,而是调用了系统的I/O,这就是来自I/O的信息
print(f.fileno())
查询文件名 f.name
f = open('filename', 'r', encoding='utf-8')
# filename
print(f.name)
判断文件是否是一个tty文件类型 f.isatty()
判断文件是否可seek f.seekable()
判断文件是否可读 f.readable()
判断文件是否可写 f.writeable()
判断文件是否关闭 f.closed()
f = open('filename', 'r', encoding='utf-8')
# f.isatty() 返回True 或 False
# f.seekable() 返回True 或 False
# f.readable() 返回True 或 False
# f.writeable() 返回True 或 False
# f.closed() 返回True 或 False
# False
print(f.isatty())
# True
print(f.seekable())
# True
print(f.readable())
# False
print(f.writable())
# False
print(f.closed)
文件的写,文件的刷新写 f.write('str') f.flush()
f = open('filename', 'w+', encoding='utf-8')
# f.write('str')是写入,但是由于内存的buffer,需要通过f.flush()刷新到文件上
f.write('我是新建的第一行。\n')
f.flush()
f.close()
f = open('filename', 'r+', encoding='utf-8')
print(f.readline())
f.write('str') f.flush() 进度条的应用技巧
import sys, time
for i in range(50):
# stdout是sys模块中的标准输出
sys.stdout.write('#')
# 写入后的强制刷新
sys.stdout.flush()
# time模块下的睡眠时间
time.sleep(0.1)
'''
程序最后会呈现是:
# ## ### #### ... ... 50个#的结果
'''
文件的截断 f.truncate(int), 如果()内不加数字,,类似于清空
f = open('filename','a+',encoding='utf-8')
# 读一行文件内的数据
f.readline()
# 打印一句话后,光标的位置
print(f.tell())
# 将光标返回到句柄2的位置
f.seek(2)
# 2
print(f.tell())
# 做一次截断,这里20并非是从句柄2开始,而是从句柄的0位开始截断
# f.truncate(20)如果赋值于变量,会返回20
# 从句柄的0位开始截断,步长为20,文件内容直接出效果
f.truncate(20)
# todo 这里会报错,类似编译编码的错
print(f.readline())
二进制模式打开文件的那些事
f = open('filename','wb')
# 如果这里不加,encode(),就会报编码的错。
#由于程序使用的二进制,但str又不是二进制格式,所以需要encode()来转译。
f.write('我是新建的第一行。\n'.encode())
文件的修改
'''
以下是filename的内容
我是第一行。
我是第二行。
我是第三行。
我是第四行。
我是第五行。
我是第六行。
'''
# 要求1将filename中‘我是第四行。’这句话替换成'我是插队的。'
# 要求2将filename中‘我是第五行。’这句话中的‘是第五行’替换成'也是来插队的,保持队形'。
f = open('filename','r', encoding='utf-8')
f_new = open('filename_new','w+', encoding='utf-8')
for line in f:
if line == '我是第四行。\n':
line = '我是插队的。\n'
elif '是第五行' in line:
line = line.replace('是第五行', '也是来插队的,保持队形')
f_new.write(line)
写在后面
- 由于打开的文件会在内存里开辟一个新的对象,如果不将其赋值,这个对象的值在文件关闭后就消失,所以要给这个内存对象赋一个变量。这个变量又称,句柄。句柄包含:文件名,字符集,大小,在硬盘上的起始位置。
- w,是以写打开文件,所以用了w等于先清空文件内容。类似创建一个文件。慎用。
- a ,追加模式,append的意思。【可读,不存在就新建,存在就追加。但是不能读】
r+ 读写模式。后面有解释。 - 如果open()内不加encoding=’utf-8’,pycharm会报错,由于windows默认的编码是gbk,python默认打开格式是unicode,所以要把utf-8编码加入。
- file.read(),默认是全部读取。file.read(5)则表示只读取5个元素(5个中文或5个数字,英文,特殊符)
- file.readlines(),只适合读取小文件,因为file.readlines()是将文件里的文件全部读出,并生产列表。
- 如果使用r+模式打开文件(可读,可写),读的时候会记录光标位置,而写始终在文件的末尾开始写。使用场景较多。
- 如果使用w+模式打开文件(可写,可读),先创建一个文件,可写,可读。如果之前文件有内容,就会清除。但是写始终在文件尾端开始。没有什么比较好的使用场景。
- 由于文件在硬盘中的存储的模式,所以文件始终在文件尾端开始。
- 使用二进制文件打开模式,rb wb ab,后面不加encoding='utf-8',因为本身就是二进制。
- 只有在网络传输打开文件时,才会用到二进制打开文件模式,rb,wb,ab。python2中还能用str模式,但是python3中只能用二进制模式。
- 文件修改的思路,一种全部加载内存,像vim一样,另一种打开一个文件,再写入一个新文件。
模式 | 说明 | 备注 |
---|---|---|
r | 只读模式 | 默认模式 |
w | 只写模式 | 只写,不读 |
a | 追加模式 | 可写,续写,不可读 |
r+ | 读写模式 | 可读,可写,建议使用这种 |
w+ | 写读模式 | 可写,可读,先重建,再读 |
a+ | 追加读写模式 | 类似r+模式 |
rb | 二进制读模式 | |
wb | 二进制读模式 | |
ab | 二进制追加写模式 |
作用 | 代码 | 备注 |
---|---|---|
打开文件 | f = open('filename','r',encoding='utf-8') | 赋值给变量 |
打开文件 | with open('filename',encoding='utf-8') as f | 文件自动关闭,且可打开多个文件 |
写文件 | f.write('str') | 非二进制写 |
写文件 | f.write('str'.encode()) | 二进制写,前提需要二进制打开 |
刷新写文件 | f.flush() | 结合f.write('str')写文件使用 |
读文件 | f.read() f.read(50) | 不加参数:全读;加参数:读参数的个数 |
读文件 | f.readline() | 读一行,带换行符,建议与.strip()配合 |
读文件 | f.readlines() | 读所有行,并返回列表形式,每一行的内容就是元素 |
截断文件 | f.truncate(int) | 如果int=空,等同于清空文件,int值等于从0位开始截断 |
查光标 | f.tell() | 返回值是int型 |
读光标复位 | f.seek(int) | int=0光标复位到文件头 |
查文件编码 | f.encoding | 注意书写格式 |
查文件名 | f.name | 注意书写格式 |
查文件句柄的位置 | f.fileno() | 返回值是int型 |
是否tty | f.isatty() | 返回值:True or False |
是否可seek | f.seekable() | 返回值:True or False |
是否可读 | f.readable() | 返回值:True or False |
是否可写 | f.writeable() | 返回值:True or False |
是否已关闭 | f.closed() | 返回值:True or False |