文件基本操作模式
要读取二进制文件,比如图片、视频等等,用’rb’, ‘wb’, 'ab’等模式打开文件即可.
- 以读的方式打开文件
r的作用:文件必须存在才可以读
f=open('passwd.bak')
print(f.read())
- 以写的方式打开文件
w的作用:
1)文件不存在时创建对应文件名的文件;
2)只可以写不可以读
3)自动清空文件
f=open('passwd.bak','w') #打开已经存有内容的文件时,再次写入会覆盖原内容
f.write('bad')#在passwd.bak文件中输入bad,并覆盖原内容
- 以读写的方式打开文件
a的作用:
1)文件不存在时创建对应文件名的文件
2)追加内容,不覆盖原文件内容
3)w的作用
a+的作用:
1)文件不存在时创建对应文件名的文件
2)追加内容,不覆盖原文件内容
3)r,w的作用
f=open('passwd.bak','a+')
f.write('bad2\n') #换行追加bad2
#seek(偏移量,位置) 位置:0(文件开头) 1(文件结尾) 偏移量:正数(向右移动几个字节)
f.seek(0.0)#a+会使指针移动到最后,因此要读取文件需要将指针移动到最开始
print(f.read())
执行结果:
#tcpdump:x:72:72::/:/sbin/nologin
#kiosk:x:1000:1000:kiosk:/home/kiosk:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
bad2
- 文件在打开会由于会占用内存资源,因此使用之后必须关闭。
f.close() #关闭文件对象
print(f.closed) #判断文件是否关闭,关闭返回True
print(f.mode) #输出文件类型
print(f.name) #输出文件名
执行结果:
True
a+
passwd.bak
- 为了方便,python中的with语句使用于对资源进行访问的场合,保证不管处理过程中是否发生错误或者异常都会自动执行规定的(“清理”)操作,释放被访问的资源,比如有文件读写后自动关闭、线程中锁的自动获取和释放等。
#with open函数可以自动释放访问的文件资源
with open('/etc/passwd') as f:
print(' in with :',f.closed) #判断with函数内文件是否关闭
print(f.readlines()[-1])#读取最后一行
print('out with :',f.closed) #判断with函数读取完文件后with外部时文件是否关闭
执行结果:
in with : False
bad2
out with : True
- readline()与readlines()的用法
#当文件比较小时,使用read、readlines()读取
#当文件比较大时,使用readline()读取
f=open('passwd.bak')
print(f.read()) #文件读取后指针返回到最后因此要将指针移动到最开始
print('*'*50)
f.seek(5.0)#移动到文件头并偏移5个字节
print(f.readline()) #readline()一行一行的读,读取第一行
print('*'*50)
f.seek(0.0)#移动到文件头并偏移5个字节
print(f.readlines()) #将每一行作为字符串组成列表
执行结果:
#sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
#tcpdump:x:72:72::/:/sbin/nologin
#kiosk:x:1000:1000:kiosk:/home/kiosk:/bin/bash
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
dhcpd:x:177:177:DHCP server:/:/sbin/nologin
bad2
bad2
**************************************************
:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
**************************************************
['#sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin\n', '#tcpdump:x:72:72::/:/sbin/nologin\n', '#kiosk:x:1000:1000:kiosk:/home/kiosk:/bin/bash\n', 'apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin\n', 'dhcpd:x:177:177:DHCP server:/:/sbin/nologin\n', 'bad2\n', 'bad2\n']
文件操作小案例
- 拷贝文件
import os
scr_filename=input('输入要拷贝的文件:')
if os.path.exists(scr_filename):#输入的文件名存在操作系统中:
dst_filename=input('拷贝到目标文件名:')
scr_f=open(scr_filename,'rb') #以读的方式打开输入的文件名对应的文件,open返回的数据流保存到scr_f中
content=scr_f.read() # 将文件内容保存到content中
dst_f=open(dst_filename,'wb') #以写的方式创建一个空文件 b表示可以打开二进制文件 :图片、视频
dst_f.write(content) #将原来保存的文件内容写入空文件中
scr_f.close() #关闭文件对象
dst_f.close()
print('copy successful')
else:
print('%s does not exit'%(scr_filename))
执行结果:
输入要拷贝的文件:passwd.bak
拷贝到目标文件名:passwd.bak2
copy successful
- 用for迭代取出open函数打开的文件内容
可迭代对象:可以使用for遍历的对象,open()返回的数据流是一个可迭代对象
from collections.abc import Iterable
f=open('passwd.bak')
print(isinstance(f,Iterable)) #f是否为可迭代对象,返回True
f.seek(0.0)
for index,line in enumerate(f):#枚举enumerate():枚举出f的索引值与文件每一行的内容
print('第%s行'%(index+1),line) #第一行索引值为0,因此+1
f.close()
执行结果:
True
第1行 #sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
第2行 #tcpdump:x:72:72::/:/sbin/nologin
第3行 #kiosk:x:1000:1000:kiosk:/home/kiosk:/bin/bash
第4行 apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin
第5行 dhcpd:x:177:177:DHCP server:/:/sbin/nologin
第6行 bad2
- 将/etc/passwd文件后5行写入passwd.bak中
f1=open('/etc/passwd')
tail_five_lines=f1.readlines()[-5:]
print(tail_five_lines,len(tail_five_lines))
f2=open('passwd.bak','w')
f2.writelines(tail_five_lines) #writelines()将列表的元素写入文件
print('writ ok')
f1.close()
f2.close()
- 读取一个文件,显示除了以井号(#)开头的行以外的所有行。
with open('passwd.bak') as f:
for line in f.readlines():#f.readlines()返回一个列表,for line in f:也可以
if not line.startswith('#'):#如果列表中每一个元素开头都不是#,就输出
print(line)
- 文件对象常用方法:
os模块
语义为操作系统,处理操作系统相关的功能,可跨平台。 比如显示当前目录下所 有文件/删除某个文件/获取文件大小……
print(os.name) #返回操作系统类型,os.name为posix是LInux ,os.name为nt系统是Windows
print('Linux' if os.name=='posix' else 'Windows' )
info=os.uname() #操作系统的详细信息
print(info.sysname) #Linux
print(os.environ)#系统的环境变量 以字典保存
print(os.environ.get('USER'))
print(os.path.isabs('/tmp/hello')) #判断是否为绝对路径(以/开头)
print(os.path.isabs('hello'))
print(os.path.abspath('hello.png')) #生成绝对路径
print(__file__) #打印当前文件名
print(os.path.join('/home/kiosk','hello.png')) #拼接返回绝对路径
print(os.path.join(os.path.abspath('hello'),'hello.png')) #将hello的绝对路径与hello.png拼接
filename='/home/kiosk/code/scq07_code/hello/hello.png'
print(os.path.basename(filename)) #获取文件名
print(os.path.dirname(filename)) #获取文件的目录名
print(os.path.dirname(__file__))#获取当前文件的目录名
print(os.path.abspath(os.path.dirname(__file__)))#获取当前文件的目录名的绝对路径
filename='hello.txt'
filename1='hello'
print(os.path.splitext(filename)) #('hello', '.txt') 分离后缀名与文件名
print(os.path.splitext(filename1)) #('hello', ' ') 没有后缀返回空字符串
filename='/home/kiosk/code/scq07_code/hello/hello.png'
print(os.path.split(filename)) #将目录和文件名分离
os.makedirs('films/film1')#在当前文件目录下递归创建目录films和ilms下的目录film1
os.mkdir('file')#在当前文件目录下创建一个子目录
os.rmdir('file')#在当前文件目录下删除子目录
os.mknod('file.txt')#在当前文件目录下创建文件
os.remove('file.txt')#在当前文件目录下删除文件
os.rename('file.txt','file2.txt')#文件重命名
print(os.path.exists('passwd.bak'))#判断文件或目录是否存在
- 案例:验证码生成器
import random
def generate_str_code(length=4):
import string
strings=string.ascii_letters+string.digits
return ''.join(random.sample(strings,length))#从strings中随机取出length个字符当作生成的验证码
white_color = (255,255,255) #画布、验证码、噪点所用到的颜色
black_color = (0,0,0,0)
green_color=(0,255,0)
bgcolor = (random.randrange(0,255),random.randrange(0,255),100)
def draw_code_image(str_code,item_width=25,height=25,point_count=100,bg_color=bgcolor,
font_color=white_color,pen_color=black_color ):
from PIL import Image,ImageDraw,ImageFont #画布,画笔,字体
width=len(str_code)*item_width #画布长宽为验证码长度*每一个验证码长度、25
height=25
im = Image.new('RGB',(width,height),bg_color)#创建画布对象,模式'RGB'为红绿蓝
draw=ImageDraw.Draw(im)#创建画笔
for i in range(point_count):#画point_count个噪点
xy=(random.randrange(0,width),random.randrange(0,height))#噪点分布为画布长度的随机位置
draw.point(xy,fill=pen_color)#噪点颜色为pen_color
font=ImageFont.truetype('wqy-microhei.ttc',23)#生成的验证码字体类型,字体大小
for index,item in enumerate(str_code):#将生成的验证码放置画布上,枚举验证码的索引和验证码元素
draw.text((5+(index*20),0),item,font=font,fill=font_color)#(5+(index*20),2):(5,2)、(25,2)、(45,2)...验证码分布位置分开,不然会在同一位值
return im #返回画布
if __name__ == '__main__':
from tqdm import tqdm
dirname='code' #此目录需建立好才能存文件
for count in tqdm(range(100)):#批量生成100个验证码文件
str_code=generate_str_code(length=5)
im=draw_code_image(str_code)
filename=os.path.join(dirname, str_code + random.choice(['.png','.jpg'])) #随机生成以.png、.jpg结尾的文件
# filename1 = os.path.join(dirname, str_code + random.choice(['.jpg'])) #将图片验证码生成器里面的所有以.png结尾的后缀名改为.jpg
im.save(filename)
#im.save(filename1)
随机生成以.png、.jpg结尾的文件执行结果:
随机生成以.jpg结尾的文件执行结果:
json模块
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的 一个子集。JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C、 C++、Java、JavaScript、Perl、Python等)。这些特性使JSON成为理想的数据交换语言。易于人阅读和编写,同时也易于机器解析和 生成(一般用于提升网络传输速率)。
python 中str类型到JSON中转为unicode类型,None转为null,dict对应object; pyhton中的集合不能转成json格式。
- 序列化
#字典转换成json数据格式:dumps/dump
import json
info=dict(a='1',b='2',c='3',猫='6')
json_info= json.dumps(info)#字典转换成json数据格式
print(info,json_info)
print(type(info),type(json_info)) #<class 'dict'> <class 'str'>
# 字典info转换json格式并存储到文件info.json中
json.dump(info,open('info.json','w'),indent=4,ensure_ascii=False) #indent=4:字典每个key-value对缩进4个,ensure_ascii=False:显示中文
print('ok')
执行结果:
{'a': '1', 'b': '2', 'c': '3', '猫': '6'} {"a": "1", "b": "2", "c": "3", "\u732b": "6"}
<class 'dict'> <class 'str'>
ok
- 反序列化
#json转换为python对象:load/loads
filename='info.json'
python_info=json.load(open(filename))
print(python_info)
print(python_info.get('猫'))
执行结果:
{'a': '1', 'b': '2', 'c': '3', '猫': '6'}
6
- json自定义编码与解码
from datetime import datetime
from datetime import date
import json
def time2str(x):
return str(x) #返回字符串类型
dt = datetime.now()
today=date.today() #today是一个日期对象不可以存入文件,需要先转换为字符串
with open('date.json','w') as f:
json.dump(today,f,default=time2str) #today转换成字符串编码成json保存到date.json
print('dump ok')
执行结果:
dump ok
#解码
python_info=json.load(open('date.json'))
print(python_info)
执行结果:
2019-12-15
编码执行结果如图:
pickle模块
python的pickle模块实现了python的所有数据序列和反序列化。与JSON不同的是pickle不是用于多种语言间的数据传输,它仅作为python对象的持久化或python程序间进行互相传输对象的方法,因此它支持了python所有的数据类型。cPickle是pickle模块的C语言编译版本相对速度更快。
- json和pickle模块的区别
1)JSON只能处理基本数据类型。pickle能处理所有Python的数据类型。
2)JSON用于各种语言之间的字符转换。pickle用于Python程序对象的持久化或者Python程序间对象网络传输,但不同版本的Python序列化可能还有差异。 - pickle序列与反序列化
from datetime import date
import pickle
today=date.today()
with open('date.pkl','wb') as f: #‘b’:日期对象today以二进制方式写入文件
pickle.dump(today,f)
print('pickle dump ok')
with open('date.pkl','rb') as f:
today=pickle.load(f)
print('pickle load ok')
print(today)
执行结果:
pickle dump ok
pickle load ok
2019-12-15
文件异常处理
- 什么是异常
Error(错误)是系统中的错误,程序员是不能改变的和处理的,如系统崩溃,内存空 间不足,方法调用栈溢等。遇到这样的错误,建议让程序终止。
Exception(异常)表示程序可以处理的异常,可以捕获且可能恢复。遇到这类异常, 应该尽可能处理异常,使程序恢复运行,而不应该随意终止异常。
AttributeError 、IOError 、ImportError 、IndexError、SyntaxError、TypeError、ValueError、KeyError、NameError
• IndentationError: 缩进错误
• KeyboardInterrupt: Ctrl+C被按下
• UnboundLocalError : 有同名的全局变量 - 异常处理机制
Python 的异常机制主要依赖 try 、except 、else、finally 和 raise 五个关键字。
• try 关键字后缩进的代码块简称 try 块,它里面放置的是可能引发异常的代码;
• except 关键字对应异常类型和处理该异常的代码块;
• 多个 except 块之后可以放一个 else 块,表明程序不出现异常时还要执行 else 块;
• finally 块用于回收在 try 块里打开的物理资源,异常机制会保证 finally 块总被执行;
• raise 用于引发一个实际的异常,raise 可以单独作为语句使用,引发一个具体的异常对象;
import os
dirname = 'dir' #不创建此目录来制造异常
filename = os.path.join(dirname, 'hello.html') # dir/hello.html
# try 关键字后缩进的代码块简称 try 块,它里面放置的是可能引发异常的代码;
try:
with open(filename, 'w') as f:
f.write('hello')
# except 关键字对应异常类型和处理该异常的代码块;
except FileNotFoundError as e:
os.mkdir(dirname)
# 如何没有产生任何异常时, 执行的内容
else:
print('no exception')
# finally 块用于回收在 try 块里打开的物理资源,异常机制会保证 finally 块总被执行
finally:
print("不管是否有异常都要执行的代码")
执行结果:
不管是否有异常都要执行的代码
执行结果图:创建了目录dir
小例子:
try:
print(10/0) # ZeroDivisionError, 异常处理之后, try里面的代码并不会继续执行。
except ZeroDivisionError as e:
print('zero')
else:
print('ok')
执行结果:
zero
- 触发异常
Python 允许程序自行引发异常,自行引发异常使用 raise 语句来完成。 raise语句中 Exception 是异常的类型(例如,NameError)参数标准异常中任一种, args 是自已提供的异常参数。raise [Exception [, args [, traceback]]]
a=input('请输入int值:')
if type(a) !=int:
raise ValueError
else:
print(a)
执行结果:
请输入int值:10
Traceback (most recent call last):
File "C:/Users/scq/Desktop/pycharmprodect/day07_code/18_抛出异常.py", line 28, in <module>
raise ValueError
ValueError
- 自定义异常
用户自定义异常都应该继承 Exception 基类或 Exception 的子类,在自定义异常类时基 本不需要书写更多的代码,只要指定自定义异常类的父类即可。
class AgeError(ValueError):
pass
age = 1000
if 0 < age < 150:
print('age legal')
else:
raise AgeError('age error')
执行结果:
Traceback (most recent call last):
File "C:/Users/scq/Desktop/pycharmprodect/day07_code/18_抛出异常.py", line 24, in <module>
raise AgeError('age error')
__main__.AgeError: age error
- Python 异常使用规范
• 不要过度使用异常
• 不要使用过于庞大的 try 块
• 不要忽略捕获到的异常