第七章 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工具,要求如下:

  1. 既可以拷贝文本又可以拷贝视频,图片等文件
  2. 用户一旦参数错误, 打印命令的正确使用方法,如 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)

    1. 文件打开方式为文本模式时,代表读取3个字符
    2. 文件打开方式为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')

results matching ""

    No results matching ""