第七章 Python文件处理
1 文件操作
1.1 文件操作步骤
#1. 打开文件,得到文件句柄并赋值给一个变量
f=open('a.txt','r') #默认打开模式就为r
#2. 通过句柄对文件进行操作
data=f.read()
#3. 关闭文件
f.close()
1.2 关于文件的关闭
# 打开一个文件包含两部分资源:操作系统级打开的文件+应用程序的变量。在操作完毕一个文件时,必须把与该文件的这两部分资源一个不落地回收,回收方法为:
f.close()
# 虽然我这么说,但是很多同学还是会很不要脸地忘记f.close(),对于这些不长脑子的同学,我们推荐傻瓜式操作方式:使用with关键字来帮我们管理上下文
with open('a.txt','w') as f:
pass
with open('a.txt','r') as read_f,open('b.txt','w') as write_f:
data=read_f.read()
write_f.write(data)
1.3 关于编码
# f=open(...)是由操作系统打开文件,那么如果我们没有为open指定编码,那么打开文件的默认编码很明显是操作系统说了算了,操作系统会用自己的默认编码去打开文件,在windows下是gbk,在linux下是utf-8。
这就用到了上节课讲的字符编码的知识:若要保证不乱码,文件以什么方式存的,就要以什么方式打开。
f=open('a.txt','r',encoding='utf-8')
2 文件打开方式
访问模式 | 说明 |
---|---|
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。** |
w | 打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。** |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。** |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。** |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。** |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。** |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。** |
w+ | 打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。** |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。** |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。** |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则将其覆盖。如果该文件不存在,创建新文件。** |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。** |
#1. 打开文件的模式有(默认为文本模式):
r ,只读模式【默认模式,文件必须存在,不存在则抛出异常】
w,只写模式【不可读;不存在则创建;存在则清空内容】
a, 之追加写模式【不可读;不存在则创建;存在则只追加内容】
#2. 对于非文本文件,我们只能使用b模式,"b"表示以字节的方式操作(而所有文件也都是以字节的形式存储的,使用这种模式无需考虑文本文件的字符编码、图片文件的jgp格式、视频文件的avi格式)
rb
wb
ab
注:以b方式打开时,读取到的内容是字节类型,写入时也需要提供字节类型,不能指定编码
#3. 了解部分
"+" 表示可以同时读写某个文件
r+, 读写【可读,可写】
w+,写读【可读,可写】
a+, 写读【可读,可写】
3 操作文件的方法
3.1 读取操作
- f.read() #读取所有内容,光标移动到文件末尾
- f.readline() #读取一行内容,光标移动到第二行首部
- f.readlines() #读取每一行内容,存放于列表中
3.2 按行读取
read_f = open('data.txt', 'r')
for line in read_f:
pass
3.3 写入操作
- f.write('1111\n222\n') #针对文本模式的写,需要自己写换行符
- f.writelines(['333\n','444\n']) #文件模式
3.4 其他操作
- f.readable() #文件是否可读
- f.writable() #文件是否可读
- f.closed #文件是否关闭
- f.encoding #如果文件打开模式为b,则没有该属性
- f.name 文件名
练习
利用b模式,编写一个cp工具,要求如下:
- 既可以拷贝文本又可以拷贝视频,图片等文件
- 用户一旦参数错误, 打印命令的正确使用方法,如
cp source_file target_file
提示:可以用import sys,然后用sys.argv获取脚本后面跟的参数
import sys
if len(sys.argv) != 3:
print('usage: cp source_file target_file')
sys.exit()
source_file,target_file=sys.argv[1],sys.argv[2]
with open(source_file,'rb') as read_f,open(target_file,'wb') as write_f:
for line in read_f:
write_f.write(line)
4 文件内 光标位置移动
f.read(3)
- 文件打开方式为文本模式时,代表读取3个字符
- 文件打开方式为b模式时,代表读取3个字节
file.seek(offset[, whence]) 设置文件当前位置
offset: -- 开始的偏移量,也就是代表需要移动偏移的字节数
whence:可选,默认值为 0。给offset参数一个定义,表示要从哪个位置开始偏移;0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起。其中1和2必须在b模式下进行
f.truncate( [ size ])
文件的打开方式必须可写,但是不能用w或w+等方式打开,因为那样直接清空文件了,所以truncate要在r+或a或a+等模式下测试效果
5 目录操作
5.1 导入OS模块
import os
5.2 目录操作方法
获取目录或文件信息
- os.stat('path/filename') 获取文件/目录信息
- os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印
- os.path.getsize(path) 返回文件/目录的大小
- os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间
- os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间
创建目录
os.mkdir('dirname') 生成单级目录;相当于shell中mkdir dirname
os.makedirs('dirname1/dirname2') 可生成多层递归目录
删除目录或文件
os.rmdir('dirname') 删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname
os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推
os.remove() 删除一个文件
修改文件或目录
- os.rename("oldname","newname") 重命名文件/目录
目录或文件判断
os.path.exists(path) 如果path存在,返回True;如果path不存在,返回False
os.path.isfile(path) 如果path是一个存在的文件,返回True。否则返回False
os.path.isdir(path) 如果path是一个存在的目录,则返回True。否则返回False
路径处理
- os.path.join(path1[, path2[, ...]]) 将多个路径组合后返回,第一个绝对路径之前的参数将被忽略
- os.path.abspath(path) 返回path规范化的绝对路径
- os.path.isabs(path) 如果path是绝对路径,返回True
- os.path.split(path) 将path分割成目录和文件名二元组返回
- os.path.dirname(path) 返回path的目录。其实就是os.path.split(path)的第一个元
- os.path.basename(path) 返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。os.path.split(path)的第二个元素
- os.path.normcase(path) 返回规范化路径 在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
6 作业
#购物车升级
#需求:
用户名和密码存放于文件中,格式为:admin|123456
启动程序后,先登录,登录成功则让用户输入工资,然后打印商品列表,失败则重新登录,超过三次则退出程序
允许用户根据商品编号购买商品
用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒
可随时退出,退出时,打印已购买商品和余额
import os
product_list = [['Iphone7',5800],
['Coffee',30],
['疙瘩汤',10],
['Python Book',99],
['Bike',199],
['ViVo X9',2499],
]
shopping_cart={}
current_userinfo=[]
db_file=r'db.txt'
while True:
print('''
登陆
注册
购物
''')
choice=input('>>: ').strip()
if choice == '1':
#1、登陆
tag=True
count=0
while tag:
if count == 3:
print('\033[45m尝试次数过多,退出。。。\033[0m')
break
uname = input('用户名:').strip()
pwd = input('密码:').strip()
with open(db_file,'r',encoding='utf-8') as f:
for line in f:
line=line.strip('\n')
user_info=line.split(',')
uname_of_db=user_info[0]
pwd_of_db=user_info[1]
balance_of_db=int(user_info[2])
if uname == uname_of_db and pwd == pwd_of_db:
print('\033[48m登陆成功\033[0m')
# 登陆成功则将用户名和余额添加到列表
current_userinfo=[uname_of_db,balance_of_db]
print('用户信息为:',current_userinfo)
tag=False
break
else:
print('\033[47m用户名或密码错误\033[0m')
count+=1
elif choice == '2':
uname=input('请输入用户名:').strip()
while True:
pwd1=input('请输入密码:').strip()
pwd2=input('再次确认密码:').strip()
if pwd2 == pwd1:
break
else:
print('\033[39m两次输入密码不一致,请重新输入!!!\033[0m')
balance=input('请输入充值金额:').strip()
with open(db_file,'a',encoding='utf-8') as f:
f.write('%s,%s,%s\n' %(uname,pwd1,balance))
elif choice == '3':
if len(current_userinfo) == 0:
print('\033[49m请先登陆...\033[0m')
else:
#登陆成功后,开始购物
uname_of_db=current_userinfo[0]
balance_of_db=current_userinfo[1]
print('尊敬的用户[%s] 您的余额为[%s],祝您购物愉快' %(
uname_of_db,
balance_of_db
))
tag=True
while tag:
for index,product in enumerate(product_list):
print(index,product)
choice=input('输入商品编号购物,输入q退出>>: ').strip()
if choice.isdigit():
choice=int(choice)
if choice < 0 or choice >= len(product_list):continue
pname=product_list[choice][0]
pprice=product_list[choice][1]
if balance_of_db > pprice:
if pname in shopping_cart: # 原来已经购买过
shopping_cart[pname]['count']+=1
else:
shopping_cart[pname]={'pprice':pprice,'count':1}
balance_of_db-=pprice # 扣钱
current_userinfo[1]=balance_of_db # 更新用户余额
print("Added product " + pname + " into shopping cart,\033[42;1myour current\033[0m balance " + str(balance_of_db))
else:
print("买不起,穷逼! 产品价格是{price},你还差{lack_price}".format(
price=pprice,
lack_price=(pprice - balance_of_db)
))
print(shopping_cart)
elif choice == 'q':
print("""
---------------------------------已购买商品列表---------------------------------
id 商品 数量 单价 总价
""")
total_cost=0
for i,key in enumerate(shopping_cart):
print('%22s%18s%18s%18s%18s' %(
i,
key,
shopping_cart[key]['count'],
shopping_cart[key]['pprice'],
shopping_cart[key]['pprice'] * shopping_cart[key]['count']
))
total_cost+=shopping_cart[key]['pprice'] * shopping_cart[key]['count']
print("""
您的总花费为: %s
您的余额为: %s
---------------------------------end---------------------------------
""" %(total_cost,balance_of_db))
while tag:
inp=input('确认购买(yes/no?)>>: ').strip()
if inp not in ['Y','N','y','n','yes','no']:continue
if inp in ['Y','y','yes']:
# 将余额写入文件
src_file=db_file
dst_file=r'%s.swap' %db_file
with open(src_file,'r',encoding='utf-8') as read_f,\
open(dst_file,'w',encoding='utf-8') as write_f:
for line in read_f:
if line.startswith(uname_of_db):
l=line.strip('\n').split(',')
l[-1]=str(balance_of_db)
line=','.join(l)+'\n'
write_f.write(line)
os.remove(src_file)
os.rename(dst_file,src_file)
print('购买成功,请耐心等待发货')
shopping_cart={}
current_userinfo=[]
tag=False
else:
print('输入非法')
else:
print('\033[33m非法操作\033[0m')