目录
导语
应用程序运行过程中产生的数据最先都是存放于内存中的,若想永久保存下来,必须要保存于硬盘中。应用程序若想操作硬件必须通过操作系统,而文件就是操作系统提供给应用程序来操作硬盘的虚拟概念,用户或应用程序对文件的操作,就是向操作系统发起调用,然后由操作系统完成对硬盘的具体操作。
一、文件的基本操作
1、我们能够操作哪些类型的文件
.txt 没有后缀名的文件
我们现在暂时不能操作word、Excel、PPT等文件。
2、如何操作文件
三步法:1、打开文件(open)
2、读或者写
3、关闭文件
(1)、打开文件
open('要操作的文件路径', '读写模式', '字符编码')
注:当路径中出现了字母和斜杠的组合会产生一些特殊的含义,所以我们应该给去掉
eg:'D:\Python27\day10\a.txt'
r'D:\Python27\day10\a.txt'
f = open(r'D:\Python27\day10\a.txt', 'r', encoding='utf-8')
# 返回的是文件句柄
print(f) # <_io.TextIOWrapper name='D:\\Python27\\day10\\a.txt' mode='r' encoding='utf-8'>
(2)、读取文件
print(f.read()) # 类似于是文件的内置方法
(3)、关闭文件
f.close()
注:第二种方式来操作文件
with上下文管理器打开文件!
as:起别名
它的特点就在于:能够自动关闭文件
with open('a.txt', 'r', encoding='utf-8') as f:
print(f.read()) # helloword
二、文件的读写模式
1、语法格式
open(文件路径,读写模式,字符编码)
文件路径:是必须写的
读写模式:也是必须写的
字符编码:可选的
2、控制文件读写操作的模式
r(只读:只能读,不能写)
w(只写:只能写,不能读)
a(append:在原来的基础之上在添加新的内容)
(1)、只读模式:
当文件路径不存在的时候,会直接保存
f = open('b.txt', 'r', encoding='utf-8') # No such file or directory: 'b.txt'
with open('a.txt', 'r', encoding='utf-8') as f:
print(f.read()) # helloword
(2)、只写模式:
写模式的特征:
1. 当文件路径不存在的时候, 会新建出来一个文件,而不报错
2. 写模式会把原来的数据覆盖掉,从新写入新的数据(重要)
with open('b.txt', 'w', encoding='utf-8') as f:
pass # 为了不全语法结构
f.write('hello') # hello
f.write('hahahahhah') # hahahahhah
f.write('jerry') # jerry
(3)、追加模式:
追加模式:当路径不存在的时候,也会新建出来文件
注:它是追加写,而不是覆盖原来的内容!
with open('c.txt', 'a', encoding='utf-8') as f:
f.write('hello world') # hello world
f.write('hello world1') # hello world1
f.write('hello world2') # hello world2
f.write('hello world3') # hello world3
f.write('hello world4') # hello world4
三、读写操作相关的方法
1、读系列
f.read() ------> read方法是一次性读取文件中得所有数据
f.readline() ------> readline一次只读文件的一行内容
f.readlines() ------> 一次性读取文件的所有内容,然后每一个内容作为列表的一个元素返回,返回的数据类型是:列表
f.writable() ------> 文件是否可读
2、写系列
f.write() ------>写入文件,只能书写字符串类型,或者二进制类型,其他类型不能够直接
f.writelines(['a', 'b']) ------>把列表中得一个一个元素当成文件的一行一行内容
f.writeable() -------->查看文件是否具备写的能力
with open('a.txt', 'w', encoding='utf-8') as f:
f.write('jerry say hello ') # jerry say hello
f.writelines(['hello\n', 'jerry\n', 'kevin\n', 'jason\n']) # hello
# jerry
# kevin
# jason
print(f.writable()) # True
print(f.readable()) # False
四、文件的读操作优化
当你读取的数据比较小的时候,其实是在缓冲区的,当数据量够多的时候,它会一定刷到磁盘
一次性读取文件的所有数据有什么问题:
当数据比较多的时候,会出现内存溢出,这种情况是坚决不能出现的
如何优化以上操作:
一点一点的读取数据然后把数据赶紧刷到硬盘里
with open('a.txt', 'r', encoding='utf-8') as f:
print(f.read()) # 一次性读取文件的所有数据,并且光标在文件的末尾,如果在去读,就读不到了
# 文件句柄f是支持for循环的
for line in f:
# line: 就是文件的一行内容
print(line)
了解的方法:
f.flush() ------>把数据从内存中立刻刷到磁盘
五、文件的操作模式
1、文本模式
t:text
r w a =====> rt wt at
文本模式默认就是操作字符串,文本
特征:
1. encoding参数必须指定
2. 读取的所有的数据都是以字符串为单位的
3. t模式只能够读取文本或者字符模式
2、二进制模式
b模式:binary
b模式中得b不能省略------------> rb wb ab
特征:
1. encoding='utf-8'参数不能够指定
2. 读取的数据全部以字节为单位
3. 二进制模式可以读取任意类型的文件
六、二进制模式下读写操作
t模式下:
f.read() 如果不指定参数,默认情况下是一次性读取所有
f.read(5) 如果指定了参数,返回的就是字符个数
b模式下:f.read(5) 如果指定了参数,返回的就是字节个数
如果文件中有中文字符,切记书写的数字要是3的倍数,如果有中文也有英文字符,这个数字需要计算了
七、控制文件内指针的移动
(1)、f.seek()
f.seek(offset, whence)
offset:偏移量
正数:往右移
负数:往左移
whence: 移动的模式
(2)、模式控制
0: 默认的模式,该模式代表指针移动的字节数是以文件开头为参照的
1: 该模式代表指针移动的字节数是以当前所在的位置为参照的
2: 该模式代表指针移动的字节数是以文件末尾的位置为参照的
# a.txt用utf-8编码,内容如下(abc各占1个字节,中文“你好”各占3个字节)
abc你好
0模式:
with open('a.txt',mode='rt',encoding='utf-8') as f:
f.seek(3,0) # 参照文件开头移动了3个字节
print(f.tell()) # 查看当前文件指针距离文件开头的位置,输出结果为3
print(f.read()) # 从第3个字节的位置读到文件末尾,输出结果为:你好
with open('a.txt',mode='rb') as f:
f.seek(6,0)
print(f.read().decode('utf-8')) #输出结果为: 好
1模式:
with open('a.txt',mode='rb') as f:
f.seek(3,1) # 从当前位置往后移动3个字节,而此时的当前位置就是文件开头
print(f.tell()) # 输出结果为:3
f.seek(4,1) # 从当前位置往后移动4个字节,而此时的当前位置为3
print(f.tell()) # 输出结果为:7
2模式:
with open('a.txt',mode='rb') as f:
f.seek(0,2) # 参照文件末尾移动0个字节, 即直接跳到文件末尾
print(f.tell()) # 输出结果为:9
f.seek(-3,2) # 参照文件末尾往前移动了3个字节
print(f.read().decode('utf-8')) # 输出结果为:好
小练习:实现动态查看最新一条日志的效果
# 小练习:实现动态查看最新一条日志的效果
import time # 导入的一个时间模块
# linux里面的一条命令:tail -f access.log
with open('access.log', mode='rb') as f:
f.seek(0, 2)
while True:
line = f.readline()
if len(line) == 0:
# 没有内容
time.sleep(0.5) # 睡眠0.5秒
else:
print(line.decode('utf-8'), end='')
八、文件的修改
mode='r+' # 可读可写
mode='w+t' # 可读可写
mode='a+t' # 可读可写
# 文件a.txt内容如下
张一蛋 山东 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
# 执行操作
with open('a.txt',mode='r+t',encoding='utf-8') as f:
f.seek(9)
f.write('<妇女主任>')
# 文件修改后的内容如下
张一蛋<妇女主任> 179 49 12344234523
李二蛋 河北 163 57 13913453521
王全蛋 山西 153 62 18651433422
强调:
1、硬盘空间是无法修改的,硬盘中数据的更新都是用新内容覆盖旧内容2、内存中的数据是可以修改的
文件修改方式一
实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
优点: 在文件修改过程中同一份数据只有一份
缺点: 会过多地占用内存
# 1. 读取文件内的所有数据
# 快捷键:shift+enter
with open('a.txt', 'r', encoding='utf-8') as f:
data = f.read()
print(data)
# 2. 读取完字符之后,做字符替换
with open('a.txt', 'wt', encoding='utf-8') as f:
f.write(data.replace('kevin', 'kevinSB'))
文件修改方式二
实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名。
优点: 不会占用过多的内存
缺点: 在文件修改过程中同一份数据存了两份
import os
with open('db.txt',mode='rt',encoding='utf-8') as read_f,\
open('.db.txt.swap',mode='wt',encoding='utf-8') as wrife_f:
for line in read_f:
wrife_f.write(line.replace('SB','kevin'))
os.remove('db.txt')
os.rename('.db.txt.swap','db.txt')