python文件操作
基本的文件操作
我们知道音频,视频和图片在硬盘中也是用二进制存储的,但是字符编码只和文本文件有关,因此'utf-8'格式的编码并不适用视频,视频有其本身的编码格式,如MP4、avi、mkv等。
一、什么是文件
文件是操作系统为用户或者应用程序提供的一个读写硬盘的虚拟文件单位。文件的操作是基于文件,即文件的操作核心就是:读和写。
就是说只要我们想要操作文件就是对操作系统发送请求,然后有操作系统将用户或应用程序 对文件的读和写操作转换成集体的硬盘指令(比如控制盘片的转动,控制机械手臂的移动,以此来读取数据。)
二、为什么要有文件?
内存无法永久保存数据,但凡我们想要永久保存数据都需要把文件保存在硬盘中,而操作文件就可以实现对硬件的操作。
文件的作用:存储数据
三、如何用文件
现在我们有一个需求需要把用户输入的账号密码存储到硬盘中,我们使用Python该如何操作呢?
name = 'chen'
pwd = '123'
3.1从硬盘中读取数据
如果我们需要打开一个文件,需要向操作系统发起请求,要求操作系统打开文件,占用操作系统的资源。python中使用open()
方法可以打开某一个具体的文件,open()方法内写入文件路径。
open(r'F:\python自学\db.txt')
想一想,如果给列表增加值,我们需要给列表赋值后才能给对应的列表加值,对文件来说也是一样的。
lis = [1,2,3]
lis.append(4)
lis.append(5)
#打开文件
f = open(r'F:\python自学\db.txt')
print(f)
#输出:
<_io.TextIOWrapper name='F:\\python自学\\db.txt' mode='r' encoding='cp936'>
打开文件后,文件不仅占用了内存,他还对应了操作系统打开的以文件,相当于使用文本编辑器打开了一个文件。并且操控文件只是为了读和写,因此打开文件并不是目的,读和写才是目的,接下来我们尝试如何读写文件。
#read 模式打开文件
f = open(r'F:\python自学\db.txt',mode='r',encoding="utf8")
#读取文件内容,向操作系统发起读请求,会被操作系统转成具体的硬盘操作,将内容由硬盘读入内存。
data = f.read()
print(data)
# 由于python的垃圾回收机制只回收引用计数为0的变量,但是打开文件还占用操作系统的资源,所以需要收回操作系统的资源
#不能使用del f
# del f 只是对变量f 的回收
f.close()
#输出:
name,123,1000
四、绝对路径和相对路径
一、绝对路径
- Windows系统绝对路径从盘符(C:\、D:\)开始写一个完整的路径。
- macos系统从根目录(/Users)开始写一个完整的路径
二、相对路径
相对于当前执行文件所在的文件夹开始找
五、文件的操作
文件操作的基础模式由三种(默认的操作模式为r模式):
- r模式为read
- w模式为write
- a模式为append
文件读写内容的格式有俩种(默认的读写内容的模式为b模式):
- t模式为text
- b模式为bytes
需要注意的是:t,b这俩种模式均不能单独使用,都需要与r模式、w模式、a模式之一连用。
一、文件打开模式(r模式)
r:read,只读模式,只能读不能写,文件不存在时报错。
f = open('F:\python自学\db.txt',mode='rt',encoding='utf-8')
data = f.read()
print(data)
print(f"type(data):{type(data)}")
f.close()
#输出:
name,123,1000
type(data):<class 'str'>
# rb:read by bytes
f = open('F:\python自学\db.txt',mode='rb')
data = f.read()
print(data)
print(f"type(data):{type(data)}")
f.close()
#输出:
b'name,123,1000\r\nname,123,1000000000\r\nname,123,100000\r\nchen,456,1222555444556\r\nchen,456,456\r\n'
type(data):<class 'bytes'>
f.read()读取文件指令会跑到文件的末端,如果在一次读取,读取的将会是空格。
f = open('F:\python自学\db.txt',mode='rt',encoding='utf-8')
data1 = f.read()
data2 = f.read()
print('data1:',data1)
print('data2:',data2)
f.close()
#输出:
data1: name,123,1000
name,123,1000000000
name,123,100000
chen,456,1222555444556
chen,456,456
data2:
由于f.read()一次性读取文件的所有内容,如果文件非常大的 话,可能会造成内存爆掉,即电脑卡死。因此可以使用f.readline()或者f.readlines()来读取文件内容。readline()读取一行,readlines()读取多行,并且以列表的形式展现的。
# f.readline()/f.readlines()
f = open('F:\python自学\db.txt',mode='rt',encoding='utf-8')
data1 = f.readline()
data2 = f.readlines()
print('data1:',data1)
print('data2:',data2)
f.close()
#输出:
data1: name,123,1000
data2: ['name,123,1000000000\n', 'name,123,100000\n', 'chen,456,1222555444556\n', 'chen,456,456\n']
二、文件打开模式之w模式
w:只能写,不能读,文件存在的时候会清空文件后在写入内容;文件不存在的时候会创建文件后写入内容。
#wt
f = open('32w.txt',mode='wt',encoding='utf-8')
print('f.readable()',f.readable())# 判断文件是否可读
f.write('chenshuaibi\n')
f.write('what,厉害')
f.write('chen,佩服啊')
f.flush()#刷新,立刻将文件内容刷到硬盘
f.close()
#输出:
f.readable() False
#wb,编码成bytes类型
f = open('33w.txt',mode='wb')
f.write('chenshuaibi'.encode('unicode_escape'))
print("type('chenshuaibi'.encode('unicode_escape'))",type('chenshuaibi\n'.encode('unicode_escape')))
f.close()
#输出:
type('chenshuaibi'.encode('unicode_escape')) <class 'bytes'>
三、文件打开之a模式
a:可以追加。文件存在,则在文件的末端写入内容;文件不存在的时候会创建文件后写入内容。
#at
f = open('35a.txt',mode='at',encoding='utf-8')
print("f.readable()",f.readable())
f.write('chen真帅')
f.close()
#输出:
f.readable() False
四、文件打开读取二进制
b模式是通用的模式,因为所有的文件在硬盘中都是以二进制的形式存储的,需要注意的是:b模式读写文件,一定不能加上encoding参数,因为二进制无法在进行编码
try:
import requests
response = requests.get(
'http://www.chenyoude.com/Python从入门到放弃/文件的三种打开模式-mv.jpg?x-oss-process=style/watermark')
data = response.content
f = open('mv.jpg?x-oss-process=style/watermark', 'wb')
f.write(data)
print('done...')
f.close()
except Exception as e:
print(e, '报错了,那就算了吧,以后爬虫处会详细介绍')
done...
f = open('34w.txt', 'wb')
f.write('nick 好帅啊'.encode('utf8'))
f.close()
六、with 管理文件操作上下文
一、with管理文件操作上下文
之前我们使用open()方法操作文件,但是open打开文件后我们还需要手动释放文件对操作系统的占用,但是其实我们可以更方便的打开文件,即python提供的上下文管理工具——with open().
with open('32.txt','rt',encoding='utf-8') as f:
print(f.read())
#输出32.txt内的内容:
大帅逼
with open()方法不仅提供自动释放操作系统占用的方法,并且with open可以使用逗号分隔,一次性打开多个文件,实现文件的快速拷贝。
#创建新文件35r.txt,将32。txt的内容复制
with open('32.txt','rb') as fr,open('35r.txt','wb') as fw:
fw.write(fr.read())
七、文件的高级应用
一、可读,可写
- r+t : 可读,可写
- w+t :可写,可读
- a+t : 可追加,可读
#wt
with open('36w.txt'.'wt',encoding='utf-8') as fw:
print(fw.readable())#检测是否可读
#输出:
False # 不能读取
print(fw.writable())#检测是否可写
#输出:
True # 可以写
#w+t
with open('36.txt','w+t',encoding='utf-8') as fw:
print(fw.readable())
#输出:
True #可读取
print(fw.writable())
#输出:
True # 可以写
#r+t
with open('36.txt','r+t',encoding='utf-8') as fw:
print(fw.readable())
#输出:
True #可读取
print(fw.writable())
#输出:
True # 可以写
二、文件内指针的移动
假设我们需要在文件内容中间的某一行增加内容,如果使用基础的r、w、a模式实现是非常困难的,因此我们需要多文件内的指针进行移动。
with open('36.txt','r+t',encoding='utf-8') as fr:
fr.readline()
fr.write('大帅逼')#写到文件最后一行
硬盘上没有修改的说法,硬盘上只有覆盖,即新内容覆盖原来的内容。
-
seek(offset,whence):offset代表文件指针的偏移量,单位是字节
# seek(offset,whence) with open('36.txt','rt',encoding='') as fr: print(f"fr.seek(3,0):{fr.seek(3,0)}")#0相当于文件头开始,1相当于当前文件所在的位置,2相当于文件末尾 #fr.seek(0,2)#切换到文件末尾
-
tell():每次统计都是从文件开头到当前指针所在的位置。
#tewll # 计算指针前面有多少字符 with open('36.txt','rt',encoding='utf-8') as fr: fr.seek(4,0) print(fr.tell())
-
read(n):只有在模式下的read(n),n代表的是字符个数,除此之外,其他但凡涉及文件指针的都是字节个数。
#read with open('36.txt','rt',encoding='utf-8') as fr: print(fr.read(3))#读出指针后n位
-
truncate(n):truncate(n)是截断文件,所以文件的打开法师必须是可写,但是不能用w、w+等方式打开,因为那样直接清空文件的内容了,所以truncate(n)要在r+、a、a+等模式下测试效果。它的参照物永远是文件头,并且truncate()如果没有参数的话,就相当于直接清空文件。
with open('36.txt','r+t',encoding='utf-8') as fr:
fr.truncate(3)
八、文件修改的俩种方式
文件的数据是存放在于硬盘上的,因而只存在覆盖,不存在修改的说法,平时我们看到我修改文件都是模拟出来的效果,具体有俩种方式。
一、方式一
将硬盘中存放在该文件的内容全部加载到内存,在内存中是可以修改的,修改完毕后,在有=由内存覆盖到硬盘(word,vim,nodpad++等编辑器)。
import os
with open('36.txt') as fr,open('36swap.txt') as fw:
data = fr.read()
data = data.replace('tank','tankSS')#进行替换修改
fw.write(data)#将信息从新新写入
#删除原文件
os.remove('36.txt')
#文件重命名
os.rename('36swap.txt','36.txt')
二、方式二
import os
with open('36.txt') as fr,open('36swap.txt') as fw:
# 循环读取文件的内容,逐行进行修改
for line in fr:
line = line.replace('nick','chen')
fw.write(line)写入修改后的信息
#删除原文件
os.remove('36.txt')
#文件重命名
os.rename('36swap.txt','36.txt')
九、补充read
####10153.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
read()
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.read()#没有参数,读取全部
print(data)
################
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
</html>
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.read(8)#有参数之后按照字节来读
print(data)
####################
<!DOCTYP
readline()
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.readline()#没有参数读取一行
print(data)
#################
<!DOCTYPE html>
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.readline(8)#有参数之后按照字节来读
print(data)
###############
<!DOCTYP
readlines()
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.readlines()#没有参数,返回一个列表,并且一行是一个数据
print(data)
####################
['<!DOCTYPE html>\n', '<html lang="en">\n', '<head>\n', ' <meta charset="UTF-8">\n', ' <title>Title</title>\n', '</head>\n', '<body>\n', '</body>\n', '</html>']
with open("10153.html",mode="r",encoding="utf8") as f:
data=f.readlines(33)#有参数的时候,返回列表,并且在参数是字节的长度,只有给我长度大于本行或者前面的所有字节,才能读到下一行,返回的是列表
print(data)
####################
['<!DOCTYPE html>\n', '<html lang="en">\n', '<head>\n']
write
with open("10152.html", mode="w", encoding="utf8") as f:
# f.writable()#清空
# f.writelines(["dd\n","ddcc\n","ll\n"])#写多行
# f.write("dd")
pass