python文件操作拓展与认识函数


目录
  • 文件内光标的移动(了解即可)
    • 前言
    • 控制光标移动seek()方法
  • 文件的修改
  • 函数
    • 语法结构
    • 简单的使用
  • 作业
  • 答案

文件内光标的移动(了解即可)

前言

在文件的内置方法中,read()方法是可以有参数的,而且在文本模式(t模式)与二进制模式(b模式)中表示不同的含义。

# 在文本模式,也就是t模式下,括号内的参数表示的是读取字符的个数
# a.txt里面的内容:我很hangsome
with open(r'a.txt', 'r', encoding='utf8') as ft:
    print(ft.read(1))  # 此时文件光标移到了第一个字符后:我'很nb
    # 输出:我
    print(ft.read(3))  # 从光标处开始读取,也就是第二个字符开始
    # 输出:很ha
    
    
# 在二进制模式,也就是b模式下,括号内的参数表示的是读取的字节数
# a.txt里面的内容:我很handsome
with open(r'a.txt', 'rb') as fb:
    # b模式读取内容需要解码,不然输出的bytes类型我们读不懂
    print(fb.read(3).decode('utf8'))  # 此时文件光标移到了第三个字节后
    # 输出:我
    print(fb.read(6).decode('utf8'))  # 从第四个字节开始读取
    # 输出:很han
    
"""在utf8中一个中文使用3字节存储,一个英文字符用1字节存储"""

控制光标移动seek()方法

seek()方法可以控制光标的移动,seek()方法有两个参数:offset和whence。

  • offset参数,代表着需要移动的字节数

  • whence参数,代表着光标起始位置,有三个选择参数:0、1、2,不写默认为0

    0:从文件的开头开始,能在文本模式和二进制模式中使用

    1:从文件的光标当前位置开始,只能在二进制模式中使用

    2:从文件的末尾开始,只能在二进制模式中使用

实战

"""a.txt中的内容为:我很hangsome"""
# 0模式
with open(r'a.txt', 'r', encoding='utf8') as f:
    f.seek(6, 0)  # 把光标向后移到离开头6个字节的位置
    print(f.read())
"""
输出:
hangsome
"""

# 1模式
with open(r'a.txt', 'rb') as f:
    print(f.read(3).decode('utf8'))  # 光标此时到了第三个字节后,也就是“我”的后面
    f.seek(7, 1)  # 把光标向后移到离当前位置7个字节的位置
    print(f.read().decode('utf8'))
"""
输出:
我
some
"""

# 2模式
with open(r'a.txt', 'rb') as f:
    f.seek(-8, 2)  # 把光标向前移到离末尾8个字节的位置
    print(f.read().decode('utf8'))
"""
输出:
hangsome
"""

文件的修改

文件本质是不可以修改的,我们所看到的新内容的出现实际上是新内容将旧内容覆盖得到的。

# 文件a.txt.的内容为:
我叫张三  今年要干一票大的

# 修改文件
with open('a.txt',mode='r+',encoding='utf-8') as f:
    f.seek(12)
    f.write('(法外狂徒)')

# 修改后的内容
我叫张三(法外狂徒)一票大的

"""只会将后面的内容覆盖,不会添加"""

那么我应该如何修改内容的同时不会把后面的内容覆盖呢?

比如我想要将“我叫张三,今年要干一票大的”修改为“我叫张三(法外狂徒),今年要干一票大的”,下面提供了两种方法。

方法一:将文件内容全部读取出来,再用replace()方法将要修改的内容替换

# a.txt的内容为
我叫张三,今年要干一票大的

# 将内容全部读取出来
with open('a.txt',mode='r',encoding='utf-8') as f:
    data=f.read()
# 将内容替换掉后写回到a.txt中
with open('a.txt',mode='w',encoding='utf-8') as f:
    f.write(data.replace('张三','张三(法外狂徒)'))
    
"""
优点:在文件修改过程中同一份数据只有一份
缺点:占用过多的内存
"""

方法二:创建一个临时的文件,将原文件内容一行行写入到临时文件中,最后将原文件删除,把临时文件名改为原文件

# a.txt的内容为
我叫张三,今年要干一票大的

import os  # 导入模块,用于操作文件

with open('a.txt', 'r', encoding='utf-8') as read_f, \
        open('.a.txt.swap', 'w', encoding='utf-8') as wrife_f:
    # 遍历原文件的每一行,并把想要修改的给替换掉
    for line in read_f:
        wrife_f.write(line.replace('张三', '张三(法外狂徒)'))
# 删除原文件
os.remove('a.txt')
# 重命名临时文件
os.rename('.a.txt.swap', 'a.txt')
    
"""
优点:内存不会占用过多
缺点:在文件修改过程中同一份数据有两份
"""

函数

其实我们在之前的学习中就已经接触过函数了,像len()、strip()、int()等等,这些我们称为内置函数。而我们接下来要学习的是自定义函数。

语法结构

def 函数名(参数1,参数2,...):
	"""函数描述"""
	函数体代码
	return 返回值

解释:

  1. def:定义函数的关键字,有了def说明这个就是函数。
  2. 函数名:自定义函数的名称,调用函数就要写函数名的,命名规范与变量名一致
  3. 括号:用于传递参数,定义函数括号一定要有。
  4. 参数:可以给函数体使用的变量,可以有多个,也可以不写
  5. 冒号:定义函数要有缩进的代码块
  6. 函数描述:用于描述函数和参数的作用
  7. 函数体代码:函数的核心,用于实现功能的代码
  8. return:用于返回数据,后面跟上什么,调用函数时就会返回什么

简单的使用

用自定义函数实现计算字符串长度的功能

def my_len(data):
    # 记录字符串个数
    count = 0
    # 遍历字符串
    for i in data:
        count += 1
    # 返回字符串个数
    return count

s = input("请输入需要计算的字符串:")
print(my_len(s))

作业

尝试着使用函数写注册登录

答案

点击查看代码
# 注册功能
def is_register(username, password):
    """
    :param username: 注册用户名
    :param password: 注册密码
    :return: 布尔值,True代表成功注册
    """
    # 获取用户信息,qwe|123,zbh|111,
    with open(r'userinfo.txt', 'r', encoding='utf8') as f:
        data = f.read()
    # 将用户隔开,['qwe|123', 'zbh|111', '']
    data_list = data.split(',')
    # 遍历用户信息
    for i in data_list:
        if username == i.split('|')[0]:
            print("用户名已存在!".center(30, '-'))
            return False
    else: # 遍历完后没有相同的用户名
        print(f'用户{username}注册成功!'.center(30, '-'))
        with open(r'userinfo.txt', 'a', encoding='utf8') as f:
            f.write(username + '|' + password + ',')
        return True
# 登录功能
def is_login(username, password):
    """
    :param username: 登录用户名
    :param password: 登录密码
    :return: 布尔值,True代表成功登录
    """
    # 获取用户信息,qwe|123,zbh|111,
    with open(r'userinfo.txt', 'r', encoding='utf8') as f:
        data = f.read()
    # 将用户隔开,['qwe|123', 'zbh|111', '']
    data_list = data.split(',')
    # 遍历用户信息
    for i in data_list:
        if username == i.split('|')[0]:
            if password == i.split('|')[1]:
                print('登录成功!!'.center(30, '-'))
                return True
            else:
                print('用户名或密码错误!!'.center(30, '-'))
                return False
    else:  # 遍历完后没有相同的用户名
        print(f'用户不存在!!'.center(30, '-'))
        return False

while True:
    print("功能列表")
    print("1.注册")
    print("2.登录")
    cmd = input("请输入你要执行的功能:")
    if cmd == '1':
        while True:
            r_username = input("请输入注册的用户名:").strip()
            r_password = input("请输入注册的密码:").strip()
            # 调用注册函数,返回True则退出循环
            if is_register(r_username, r_password):
                break
    elif cmd == '2':
        while True:
            l_username = input("请输入用户名:").strip()
            l_password = input("请输入密码:").strip()
            # 调用登录函数,返回True则退出循环
            if is_login(l_username, l_password):
                break
    else:
        print("请输入正确的指令!!".center(30, '-'))