一 什么是文件
文件是操作系统提供给用户/应用程序操作硬盘的一种虚拟的概念/接口
用户/应用程序
操作系统(文件)
计算机硬件(硬盘)
二 为何要用文件
用户/应用程序可以通过文件将数据永久保存在硬盘中,即操作 文件就是操作硬盘
用户/应用程序直接操作的是文件,对文件进行的所有的操作,都是在向操作系统发送系统调用,然后再由操作将其转换成具体的硬盘操作
三 如何用文件:open()
控制文件读写内容的模式:t和b
强调:t和b不能单独使用,必须跟r/w/a连用
1、t文本(默认的模式)
1、读写都以str(unicode)为单位的
2、文本文件
3、必须指定encoding='utf-8'
2、b二进制/bytes
b:binary 模式
1、读写都是以 bytes 为单位
2、可以针对所有模式
3、b 模式下,一定不能指定字符编码,即一定不能指定 encoding参数
总结:
1、在操作纯文本方面 t 模式帮我们省去了编码与解码的环节
2、针对文本文件(如图片、视频、音频等)只能使用 b 模式
通用模式为 b 模式
bytes 类型转换
x = 10 #int(10)
'你'.encode('gbk') # bytes( )
控制文件读写操作的模式:
r只读模式
w只写模式
a只追加写模式
+:r+、w+、a+
ps:
x 模式(控制文件操作的模式)-->了解
x:只写模式(不可读,不存在则创建,存在则报错)
x+ :可读可写
四 文件基本操作
1、打开文件
windows 路径分隔符问题解决方法:
绝对路径:
从根目录下一层一层找
open(r 'c:/a/nb/c.text ') #假如写右斜杠也行,open()会帮你转换成,用 r 表示告诉你这只是普通的字符,没有转义
相对路径:
必须以当前文件为基准
open('c.txt') #打开文件, 后面才能操作文件内容
f = open('c.txt' mode='rt') #f的值是一种变量,占用的应用程序的内存空间,open操作占用操作系统的内存(因为它想操作系统发送的打开文件的请求)
print(f)
2、操作文件:读/写文件
应用程序对文件的读写请求都是在向操作系统发送系统调用,然后由操作系统控制硬盘把输入读入内存、或者写入硬盘。
res = f.read()#向操作系统发送请求,把文件读入内存
print(res)
3、关闭文件
f.close( ) # 关闭文件, 回收操作系统资源
f.read( ) #变量 f 是仍然存在的,但是不能再读了
#del f #回收应用程序资源 在 python 中回收应用程序资源不需要考虑,python 会帮你回收
五 with 上下文管理
由于大部分程序员还是会不由自主地忘记f.close(),考虑到这一点,python提供了with关键字来帮我们管理上下文
f:文件句柄
with open('a.txt' mode='rt')as f: # ===> f= open('a.txt' mode='rt')
res = f.read()
print(res)
with open('a.txt' mode='rt')as f1,
open('b.txt' mode='rt')as f2:
res1 = f1.read()
res2 = f2.read()
print(res1)
print(res2)
2、指定字符编码
强调:t 和 b 不能单独使用, 必须跟 rwa 连用
t 文本(默认的模式):
1、读写都以 str(unicode)为单位的
2、文本文件
3、必须指定 encoding = 'utf-8'
没有指定 encoding 参数操作系统会使用自己默认的编码
linux 系统默认 utf-8
windows 系统默认 gbk
with open('c.txt', mode='rt', encoding= 'utf-8')as f:
res= f.read() #t模式会将 f.read()读出的结果解码成 unicode
print(res, type(res))
内存:utf-8格式的二进制----------解码--------------->unicode
硬盘:c.txt内容:utf-8格式的二进制
3、文件操作模式详解
以t模式为基础进行内存操作
1、r(默认的操作模式):只读模式,当文件不存在时报错,当文件存在时文件指针跳到开始位置
with open('c.txt',mode='rt',encoding='utf-8') as f:
print('第一次读'.center(50,'*'))
res=f.read() # 把所有内容从硬盘读入内存
print(res) #哈哈哈哈
print('第二次读'.center(50,'*'))
res1=f.read()
print(res1)#换行符
案例:
inp_username=input('your name>>: ').strip()
inp_password=input('your password>>: ').strip()
with open('user.txt',mode='rt',encoding='utf-8') as f:
for line in f:
# print(line,end='') # egon:123
username,password=line.strip().split(':')
if inp_username == username and inp_password == password:
print('login successfull')
break
else:
print('账号或密码错误')
应用程序======》文件
应用程序=》数据库管理软件=》文件
2、w:只写模式,当文件不存在时会创建空文件,当文件存在会清空文件,指针位于开始位置
注:如果重新以w模式打开文件,则会清空文件内容
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.read() # 报错,不可读
f.write('擦勒
')
在以w模式打开文件没有关闭的情况下,连续写入,新的内容总是跟在旧的之后
with open('d.txt',mode='wt',encoding='utf-8') as f:
f.write('擦勒1
')
f.write('擦勒2
')
f.write('擦勒3
')
w 模式一般用来创建全新的文件
文本文件的 copy 工具
src_file=input('源文件路径>>: ').strip()
dst_file=input('源文件路径>>: ').strip()
with open(r'{}'.format(src_file),mode='rt',encoding='utf-8') as f1,
open(r'{}'.format(dst_file),mode='wt',encoding='utf-8') as f2:
res=f1.read()
f2.write(res)
3、a:只追加写,在文件不存在时会创建空文档,在文件存在时文件指针会直接调到末尾
with open('e.txt',mode='at',encoding='utf-8') as f:
# f.read() # 报错,不能读
f.write('擦嘞1
')
f.write('擦嘞2
')
f.write('擦嘞3
')
w 模式 与a 模式 的异同:
1、相同点:在打开的文件不关闭的情况下,连续的写入,新写的内容总会跟在前写的内容之后;
2、不同点:以 a 模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件;
案例:a模式用来在原有的文件内存的基础之上写入新的内容,比如记录日志、注册
注册功能
name=input('your name>>: ')
pwd=input('your name>>: ')
with open('db.txt',mode='at',encoding='utf-8') as f:
f.write('{}:{}
'.format(name,pwd))
了解:+ 不能单独使用,必须配合 r、w、a,而且它是继承自己(r/w/a)的特性的。其实就是在(r/w/a)的基础特性上增加了一个可读可写的功能。
with open('a.txt',mode='r+t', encoding='utf-8')as f:
print(f.read()) #读出硬盘的二进制 —>t模式控制将二进制转换成unicode->字符。
f.write('中国')
with open('a.txt', mode='w+', encoding='utf-8')as f:
print(f.read()) # 读不到 ,w 模式下文件以前的数据会被清除
f.write('中国
')
f.write('222
')
f.write('333
')
print(f.read())#读不到, 指针处于末尾位置
with open('a.txt', mode='a+', encoding='utf-8')as f:
print(f.read()) #读不到,因为 a模式下指针会指向末尾位置
f.write('中国
')
print(f.read()) #读不到,写入后指针还是处于末尾位置
Ps:
open(打开文件(文件很大))是不涉及读和写操作的,只是将文件指针控制到开头或者末尾,并不会阻塞,当data =f.read()(赋值:把硬盘的内容读入内存)操作时,才会会阻塞。
错误演示:t 模式只能读文本文件
with open('qq.mp4', mode='rt', encoding='utf-8')as f:
f.read()#硬盘的二进制读入内存->t 模式会将读入内存的内容进行 decode解码操作
以b模式为基础进行内存操作
b 模式下:硬盘文件内容读入内存是不做任何转换的
一定不能指定 encoding 参数
读写都是以 bytes
with open(r'a.txt', mode='rb')as f:
res = f.read() #硬盘的二进制(utf-8格式)直接读入内存->b模式下不做转换
print(res,type(res)) #b'xe4xbdxa0xe5xa5xbd' class<bytes> -->当成二进制
print(res.decode('utf-8'))#你好
b 模式下:不能写入字符串格式数据,所以需要 encode成硬盘的编码格式(utf-8)
with open('a.txt', mode='wb')as f:
f.write('你好')#报错
f.write('你好'.encode('utf-8'))
with open(r'b.txt', mode='wb')as f:
f.write('你好 hello'.encode('gbk')) #��� hello #你好显示乱码是因为pycharm打开默认是 utf-8解码,所以使用gbk编码导致中文显示会乱码
文件拷贝工具
src_file=input('源文件路径>>: ').strip()
dst_file=input('源文件路径>>: ').strip()
with open(r'{}'.format(src_file),mode='rb') as f1,
open(r'{}'.format(dst_file),mode='wb') as f2:
# res=f1.read() # 内存占用过大
# f2.write(res)
for line in f1:
f2.write(line)
4、循环读取文件
方式一 : while + f.read(数据长度参数)
数据长度参数:自己控制每次读取的数据量
数据长度为字节长度
with open(r'test.jbg', mode='rb')as f:
while True:
res = f.read(1024)#1024个字节
if len(res)== 0:
break
print(len(res)) #1024
方式二: for : 以行数为单位读, 当一行内容过长时会导致一次性读入内存的数据量过大
for 循环区分行是以换行符区分的
with open(r'g.txt', mode='rb')as f:
for line in f:
print(line, len(line))
注:当文件内容一行过长时,可以用 while,它可以控制每次读取的量
f.readline:一次读一行
相当于 for 循环,不指定默认每次读一行
f.readline(n):
t模式下:
1)当 n 不超过一行字符个数时,读n 个字符
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rt', encoding='utf-8') as f:
res = f.readline(2)
print(res) ##你好 t模式下read(n): n代表的是字符个数
2)当 n超过一行字符个数时,读一行字符
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rt', encoding='utf-8') as f:
res = f.readline(100)
print(res) #你好 hello
#空行(换行符)
b 模式下:
n 代表的是字节数
f.readlines:一次读所有行
f.readlines( ):默认读所有行,存放于列表中
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rt', encoding='utf-8') as f:
res = f.readlines()
print(res) #['你好 hello
', 'haha
', '1111
']
f.readlines( n): t 模式下的n 代表读的字符数
1)如果字符数没有超过一行的字符数,那么就读一行
2)如果字符数超过或等于一行的字符数,指针会读到换行符移至第二行,所以也会读取下一行内容,依次往下类推
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rt', encoding='utf-8') as f:
res = f.readlines(1)
print(res) #['你好 hello
']
res = f.readlines(9) #读到了
print(res) #['你好 hello
', 'haha
']
res = f.readlines(13)
print(res) #['你好 hello
', 'haha
']
['你好 hello
', 'haha
', '1111
']
f.read( n): b 模式下的n 代表读的字节数
with open('1.mp4',mode='rb') as f:
while True:
data=f.read(1024) # 同一时刻只读入1024个Bytes到内存中
if len(data) == 0:
break
print(data)
强调:
f.read( )与 f.readlines( )都是将内容一次性读入内存,如果内容过大会导致内存溢出。
5、循环写入操作
f.writelines( 列表)
t 模式下写入时, 列表内部的元素必须为字符串类型,相当于一个 for 循环写入
with open('h.txt',mode='wt',encoding='utf-8') as f:
# f.write('1111
222
3333
')
# l=['11111
','2222','3333',4444] #列表中的有元素为不是字符串类型,所有写入是会报错
l=['11111
','2222','3333']
# for line in l:
# f.write(line)
f.writelines(l)
b模式下写入时,必须要将字符串类型 进行encode成 ’ 硬盘类型编码格式’,否则 f.write( )报错
with open('h.txt', mode='wb')as f:
l = [
'111aa
'.encode('utf-8'),
'222bb
'.encode('utf-8'),
]
f.writelines(l)
补充:
#如果字符串是是纯数字,英文字符组成,可以直接加前缀b 得到 bytes 类型
l = [
b'111aa
',
b'222bb
'
]
#'上'.encode('utf-8')等同于 bytes('上', encoding='utf-8')
l = [
bytes('上啊
',encoding='utf-8'),
bytes('冲啊
',encoding='utf-8')
]
f.flush
立即将文件内容从内存存入硬盘
一般会用于文件测试
with open('h.txt', mode='wt',encoding='utf-8') as f:
f.write('哈')
# f.flush()
了解:
f.readable( ) :文件是否可读
f.writeable( ):文件是否可写
f.closed : 文件是否关闭
f.encoding :如果文件打开模式为 b,则没有该属性
f.flush( ): 立刻将文件内容从内存刷到硬盘
f.name: 文件名
with open('aaa.txt', mode='wt', encoding='utf-8') as f:
print(f.readable()) #False
print(f.writable()) #True
print(f.name) #aaa.txt
print(f.encoding) #utf-8
六 控制文件指针操作
指针移动的单位都是以 bytes(字节)为单位,只有一种情况特殊:t模式下的 read( n) ,n 代表的是字符个数
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rt', encoding='utf-8') as f:
res = f.read(4)
print(res) #你好 h
1、f.seek:移动指针
f.seek( n,模式): n 指的是移动的字节个数
注:不管是否是在 t 或者 b 模式下,f.seek都是以字节个数移动
模式
模式 0:参照物是文件开头位置
f.seek(9,0)
f.seek(3,0) # 3
模式 1:参照物是当前指针所在位置
f.seek(9,1)
f.seek(3,1) # 12
模式2:参照物是文件末尾位置,应该倒着移动
f.seek(-9,2)#3
f.seek(-3,2)#9
强调:
t模式下只能使用模式 0,而b 模式下可以使用模式 0,1,2
'''
你好 hello
haha
1111
'''
with open('aaa.txt', mode='rb') as f:
f.seek(2, 0) #2
f.seek(3, 0) #3
print(f.tell()) #3
res =f.read()
print(res) #b'xe5xa5xbd hello
haha
1111'
print(res.decode('utf-8'))
'''
好 hello
haha
1111
'''
Ps:硬盘压根没有修改操作,都是新数据完全覆盖旧数据;都是修改内存的数据保存覆盖硬盘原数据。
七 文件修改
文件修改的两种方式
方式一:文本编辑采用的就是这种方式
实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
优点:在文件修改过程中同一份数据只有一份(硬盘)
缺点:会过多地占用内存
with open('c.txt',mode='rt',encoding='utf-8') as f:
res=f.read()
data=res.replace('alex','dsb')
print(data)
with open('c.txt',mode='wt',encoding='utf-8') as f1:
f1.write(data)
方式二:
实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
优点:不会占用过多的内存
缺点: 在文件修改过程中同一份数据存了两份(硬盘)
with open('c.txt', mode='rt', encoding='utf-8') as f,
open('.c.txt.swap', mode='wt', encoding='utf-8') as f1:
for line in f:
f1.write(line.replace('alex', 'dsb'))
os.remove('c.txt')
os.rename('.c.txt.swap', 'c.txt')