第五章:文件处理

第五章 文件处理

一、什么是文件?

文件是操作系统提供给用户 / 应用程序操作硬盘的一种虚拟的概念 / 接口
  用户 / 应用程序
  操作系统(文件)
  计算机硬件(硬盘)

二、为何要用文件?

用户 / 应用程序可以通过文件将数据永久保存到硬盘中(即操作文件就是操作硬盘)
用户 / 应用程序直接操作的是文件,对文件进行的所有的操作
都是在向操作系统发送系统调用,然后再由操作系统将其转换成具体的硬盘操作

三、如何使用文件

open() 打开文件
控制文件读写内容的模式:t和b
强调:t和b不能单独使用,必须跟r / w / a连用
t:文本(默认的模式)
  1.
读写都是以str(Unicode)为单位的
  2.
文本文件
  3.
必须为open()
指定encoding = 'utf-8'

b:二进制 / bytes
  控制文件读写操作的模式:
    r:只读模式
    w:只写模式
    a:只追加写模式
    +:r +、w +、a +

四、文件基本操作

1.打开文件
① Windows路径分隔符问题:
open('C:\a\nb\c\d.txt')
解决方案1:(推荐)
open(r'C:\a\nb\c\d.txt')  # 路径前面加r,取消转义字符的作用
解决方案2open('C:/a/nb/c/d.txt')  # 系统自动识别为路径open() 操作既占用应用程序,还占用操作系统
f = open(r'F:\Python学习相关\正课\第2周\day05\world.txt', mode='rt')
# f的值是一种变量,占用的是应用程序的内存空间
print(f)

x = 10  # 属于 应用程序:Python解释器 的内存空间
③ 绝对路径 & 相对路径(了解)
  绝对路径:(就是文件的完整路径)

    优点:路径完整,易于寻找

    缺点:路径名可能过长,前路径修改后,文件就找不到

C:\Users\Darker\Desktop\a.txt
  相对路径:(当前文件夹所在的路径)

    优点:路径相对剪短

    缺点:文件换个文件夹就不以寻找

a.txt
2.操作文件(读 / 写文件)
应用程序读文件的读写请求都是在向操作系统发送系统调用,然后由操作系统控制硬盘把输入读入内存、或者写入硬盘
f = open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt', encoding='UTF-8')
res = f.read()
print(res)
文件对象又称为:文件句柄
with open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt', encoding='UTF-8') as f:
    res = f.read()
    print(res)
3.关闭文件
del f
f.close()
文件名过长的时候,可以用“\”转义字符,来表示是同一行
with open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt', encoding='UTF-8') as f1, \
        open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt', encoding='UTF-8') as f2:
    res1 = f1.read()
    res2 = f2.read()

    print(res1)
    print(res2)

五、指定字符编码

没有指定encoding参数,操作系统会使用自己默认的编码
with open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt') as f1:
    res1 = f1.read()  # t模式会将f.read()读出的结果解码成Unicode
    print(res1, type(res1))

# 此时,就会报错:
UnicodeDecodeError: 'gbk'
codec
can
't decode byte 0x80 in position 16: illegal multibyte sequence
linux系统、MacOS系统默认UTF - 8
Windows系统默认GBK
内存:utf - 8
格式的二进制 - ---解码 - ---Unicode
硬盘(aaa.txt内容:utf - 8
的二进制)

六:文件操作r\w\a模式详解

下面内容都是以t模式为基础,进行内存操作的
1.r(默认的操作模式)只读模式
当文件不存在时:会报错
当文件存在时:文件指针调到开始位置
with open(r'C:\Users\Darker\Desktop\aaa.txt', mode='rt', encoding='UTF-8') as f:
    print('第一次读'.center(50, '*'))
    res = f.read()  # 把所有内容从硬盘读到内存
    print(res)

    print('第二次读'.center(50, '*'))
    res1 = f.read()  # t模式会将f.read()读出的结果解码成Unicode
    print(res1)

** ** ** ** ** ** ** ** ** ** ** *第一次读 ** ** ** ** ** ** ** ** ** ** ** *
滚滚长江东逝水
滚滚长江东逝
滚滚长江东
滚滚长江
滚滚长
滚滚
滚
** ** ** ** ** ** ** ** ** ** ** *第二次读 ** ** ** ** ** ** ** ** ** ** ** *
== 案例
user.txt中的内容:
qwe: 123
asd: 456
zxc: 789
    

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:
        l = line.strip().split(':')
        username, password = line.strip().split(':')
        if inp_username == username and inp_password == password:
            print('Successful')
            break
    else:
        print('False')
应用程序 == == ==》文件
应用程序 == == ==》数据库管理软件 == == ==》文件
2.w 只写模式
当文件不存在时:会创建空文件
当文件存在时:会清空文件,文件指针调到开始位置
with open('d.txt', mode='wt', encoding='utf-8') as f:
    # f.read()  #只能写,不能读
    f.write('111\n123')  # 先清空内容,再写入
强调1:
  在以w模式打开文件没有关闭的情况下,连续写入,新写的内容总是跟在旧写的内容之后

with open('d.txt', mode='wt', encoding='utf-8') as f:
    # f.read()  #只能写,不能读
    f.write('111\n')  # 先清空内容,再写入
    f.write('222\n')  # 先清空内容,再写入
    f.write('333\n')  # 先清空内容,再写入
强调2:
  如果重新以w模式打开文件,则会清空文件

with open('d.txt', mode='wt', encoding='utf-8') as f:
    f.write('111\n')  # 先清空内容,再写入
with open('d.txt', mode='wt', encoding='utf-8') as f:
    f.write('222\n')  # 先清空内容,再写入
with open('d.txt', mode='wt', encoding='utf-8') as f:
    f.write('333\n')  # 先清空内容,再写入
案例: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\n')
    f.write('我去2\n')
    f.write('我去3\n')
强调
w模式
与
a模式的异同:
1.相同点
    在打开文件
不关闭的情况下,连续的写入,新写的内容总会跟在之前写的内容之后

2.不同点
    以a模式重新打开文件,不会清空原文件内容,会将文件指针直接移动到文件末尾

    以为w模式重新打开文件,会清空原文件内容,会将文件指针移动到文件开头

案例:a模式用来在原有的文件内存的基础之上,写入新的内容,比如:记录日志、注册功能
注册功能:
name = input('请输入用户名:')
pwd = input('请输入密码:')
with open('db.txt', mode='at', encoding='utf-8') as f:
    f.write('{}:{}\n'.format(name, pwd))

七、了解

+模式:+不能单独使用,必须配合r、w、a

r + 模式:文件不存在,则会报错
w + 模式:文件不存在,则会创建新文件
r + 模式:文件不存在,则会报错

八、控制文件内指针的移动

# f.seek(字节个数,模式)
# 模式有三种
# 0:参照文件的开头
# 1:参照当前所在的位置
# 2:参照文件末尾的位置

# 注意:
# 1、无论何种模式,都是以字节单位移动,只有t模式下的read(n)的n代表的是字符个数
with open('a.txt',mode='rt',encoding='utf-8') as f:
    data=f.read(6)
    print(data)
with open('a.txt',mode='rt',encoding='utf-8') as f:
    data = f.read(6)
    print(data)
with open('a.txt',mode='rt',encoding='utf-8') as f:
    data = f.read(6)
    print(data)  #打印的是字符hello美

with open('a.txt',mode='rb') as f:
    data = f.read(6)
    print(data)  #显示的是字节b'hello\xe7'
with open('a.txt',mode='rb')as f:
    data = f.read(6)
    print(data)

with open('a.txt',mode='rb') as f:
    data=f.read(5)
    print(data.decode('utf-8'))
with open('a.txt',mode='rb',)as f:
    data = f.read(5)
    print(data.decode('utf-8'))
with open('a.txt',mode='rb') as f:
    data = f.read(5)
    print(data.decode('utf-8'))
with open('a.txt',mode='rb') as f:
    data = f.read(5)
    print(data.decode('utf-8'))

# 2、只有0模式可以在t模式下使用,而0、1、2都可以在b模式下用

# 示例
with open('a.txt',mode='rt',encoding='utf-8') as f: #t模式下1,2模式会报错
    f.seek(3,2)
with open('a.txt',mode='rb',encoding='utf-8') as f:
    f.seek(0,0)

with open('a.txt',mode='rb') as f:
    f.seek(6,0)
    print(f.read().decode('utf-8'))
    f.seek(16,1)
    print(f.tell())
with open('a.txt',mode='rb')as f:
    f.seek(5,0)
    print(f.read().decode('utf-8'))
with open('a.txt',mode='rb') as f:
    f.seek(8,0)
    print(f.read().decode('utf-8'))
    f.seek(19,1)
    print(f.tell())

    f.seek(-3,2)
    print(f.read().decode('utf-8'))

    f.seek(0,2)
    print(f.tell())



with open('b.txt',mode='wt',encoding='utf-8') as f:
    f.seek(10,0)
    print(f.tell())
    f.write("你好")


# 应用1:tail -f access.log
import time
with open('access.log',mode='rb') as f:
    f.seek(0,2)
    while True:
        line=f.readline()
        if len(line) == 0:
            time.sleep(0.3)
        else:
            print(line.decode('utf-8'),end='')

九、文件操作的其他方法

with open('b.txt',mode='rt',encoding='utf-8') as f:
    data=f.readlines()
    print(data,end=' ')
print()

with open('b.txt',mode='wt',encoding='utf-8') as f:
    # f.write("1111\n222\n3333\n")

    lines=["aaaa\n",'bbb\n','cccc\n']

    for line in lines:
        f.write(line)

    f.writelines(lines)
    f.writelines("hello")
    f.write("hello")

with open('b.txt',mode='wt',encoding='utf-8') as f:
    f.write('hello\n')
    f.write('world\n')
    f.flush()


with open('b.txt',mode='r+t',encoding='utf-8') as f:
    f.truncate(4)

十、文件修改

10.1文件修改low

a.txt

张一蛋     山东    179    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

test.py

with open('a.txt',mode='r+t',encoding='utf-8') as f:
    res = f.read(9)	# 读取前9个字符:张一蛋     山
    print(res)
    f.seek(9,0)		# 把指针移到第9个bytes
    f.write('<男妇女主任>')	# 一个汉字对应3个bytes,此处共有3*5+2=17个bytes

修改后a.txt的内容

张一蛋<男妇女主任>9    49    12344234523
李二蛋     河北    163    57    13913453521
王全蛋     山西    153    62    18651433422

10.2 文件修改的2种方式

**方式一:**文本编辑采用的就是这种方式

# 实现思路:将文件内容发一次性全部读入内存,然后在内存中修改完毕后再覆盖写回原文件
#   优点: 在文件修改过程中同一份数据只有一份
#   缺点: 会过多地占用内存

# 文件的读取

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('111')

**方式二:**import os

# 实现思路:以读的方式打开原文件,以写的方式打开一个临时文件,一行行读取原文件内容,
# 修改完后写入临时文件...,删掉原文件,将临时文件重命名原文件名
#   优点: 不会占用过多的内存
#   缺点: 在文件修改过程中同一份数据存了两份

# 在c.txt中的内容:
life is beautiful
dream is beautiful
learn is beautiful

# 执行文件
import os     # 导入OS模块

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'))  # 把alex替换为dsb

os.remove('c.txt') # 删除原文件
os.rename('.c.txt.swap', 'c.txt')  # 把临时文件重命名为原文件

# 执行后,c.txt中的内容
# dsb is sb
# sb is dsb
# egon is hahahahah

作业

# 1.编写文件copy工具
# 2.编写登录程序,账号密码来自于文件
# 3.编写注册程序,账号密码来存入文件
# 4.编写用户登录接口
# 5.通用文件copy工具实现
# 6.基于seek控制指针移动,测试r+、w+、a+模式下的读写内容
# 7.tail -f access.log程序实现

答案

# 1.编写文件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)
# 2.编写登录程序,账号密码来自于文件
print("========欢迎来到登录界面========")
inp_name = input("请输入用户名:").strip()
inp_pwd = input("请输入密码:").strip()
with open(r'userinfo.txt', 'rt', encoding='UTF-8') as f:
    for line in f:
        user, pwd = line.strip().split(':')
        if user == inp_name and pwd == inp_pwd:
            print('恭喜您,登录成功!')
            break
    else:
        print('用户名或密码错误!')
print("==============================")
userinfo.txt的内容:
	qwe:123
	asd:456
	zxc:789
        
# 3.编写注册程序,账号密码来存入文件
print("========欢迎来到注册界面========")
inp_user = input("请输入用户名:").strip()
inp_pwd = input("请输入密码:").strip()
with open(r'userinfo1.txt', 'at', encoding='utf-8') as f:
    f.write('{}:{}\n'.format(inp_user,inp_pwd))
print("============注册成功============")

# 4.编写用户登录接口
'''
1.输入账号密码完成验证,验证通过后输出"登录成功"
2.可以登录不同的用户
3.同一账号输错三次锁定,(提示:锁定的用户存入文件中,这样才能保证程序关闭后,该用户仍然被锁定)'''
import os
list2=[]
tag = True
while True:
    print('''
    1.注册
    2.登录
    3.退出
    ''')
    tag = True
    cmd = input("请输入指令>")
    list1 = ["1","2","3"]
    if cmd == list1[0]:
        username = input("请输入要注册的用户名:")
        password = input("请输入要注册的密码:")
        with open("a.txt","a",encoding="utf-8") as f :
            # f.write(f"{username}:{password}\n")
            f.write("{}:{}\n".format(username,password))
    elif cmd == list1[1]:
        while tag:
            user_inp = input("请输入你的用户名:")
            if os.path.exists(f"locked/{user_inp}"):
                print("账号被锁定")
                tag =False
                continue
            else:
                pwd_inp = input("请输入你的密码:")
                with open("a.txt","r",encoding="utf-8") as f:
                    for line in f:
                        username,password = line.strip().split(":")
                        if username == user_inp and password == pwd_inp:
                            print("登录成功")
                            break
                    if list2.count(user_inp) == 2:
                        with open(f"locked/{user_inp}","w",encoding="utf-8"):
                            print("错误太多被锁定")
                    else:
                        print("输入错误")
                        list2.append(user_inp)
                        print(list2.count(user_inp))
    elif cmd == list1[2]:
        print("谢谢")
        break
    else:
        print("错误输入")

        
# 5.通用文件copy工具实现
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)
        
# 6.基于seek控制指针移动,测试r+、w+、a+模式下的读写内容
# r+
with open(r'b.txt',mode='r+t',encoding='utf-8') as f:
    print(f.read())     # 打印b.txt中的内容,内容为:123456789,光标会移至末尾
    f.seek(5,0)     # 将指针移到第5个字符
    print(f.tell())     # 打印当前指针位置,为5
    f.write('qwe')     # 写入qwe,替换6-8个字符
    f.seek(0, 0)        # 再将指针移到开头
    print(f.read())     # 再次打印b.txt中的内容,内容为:12345qwe9
# w+
with open(r'b.txt',mode='w+t',encoding='utf-8') as f:
    print(f.read())     # w模式会清空文件的内容,此时打印内容为空,指针在开头
    f.seek(10,0)     # 将指针移到第10个字符
    print(f.tell())     # 打印当前指针位置,为10
    f.write('qwe')     # 写入qwe,替换11-13个字符
    f.seek(0, 0)        # 再将指针移到开头
    print(f.read())     # 再次打印b.txt中的内容,内容为:          qwe
# a+
with open(r'b.txt',mode='a+t',encoding='utf-8') as f:
    print(f.read())     # a模式不会清空文件的内容,指针在末尾
    f.seek(5,0)     # 将指针移到第5个字符
    print(f.tell())     # 打印当前指针位置,为5
    f.write('qwe')     # 写入qwe,会在末尾写入qwe
    f.seek(0, 0)        # 再将指针移到开头
    print(f.read())     # 再次打印b.txt中的内容,内容为:123456789qwe
    
# 7.tail -f access.log程序实现
while 1:
    print('输入任意文字可添加至日志,输入readlog可读取日志信息')
    msg = input('输入指令:').strip()
    if msg == 'readlog':
        with open(r'access.log', 'a+b') as f:
            f.write(bytes('{}\n'.format(msg), encoding='utf-8'))
            f.seek(0, 0)
            log = f.read().decode('utf-8')
            print(log)
        continue
    else:
        with open(r'access.log', 'ab') as f:
            f.write(bytes('{}\n'.format(msg), encoding='utf-8'))

作者:吴常文
出处:https://blog.csdn.net/qq_41405475
本文版权归作者和CSDN共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

猜你喜欢

转载自blog.csdn.net/qq_41405475/article/details/113529571