zoukankan      html  css  js  c++  java
  • Python正课58 —— 小说阅读项目 初级

    本文内容皆为作者原创,如需转载,请注明出处:https://www.cnblogs.com/xuexianqi/p/12600935.html

    一:图片

    目录结构:

    dir

    bin

    start.py

    start

    conf

    settings.py

    s

    core

    src.py

    src

    db

    foctions

    egon流浪记 - 序曲.txt

    序曲

    成长之路 - 起源.txt

    起源

    绿色的光 - 毁灭.txt

    毁灭

    egon再临 - 重生.txt

    重生

    父子局 - 轮回.txt

    轮回

    egon养成攻略 - 终章.txt

    终章

    db.txt

    
    

    db_handler

    db_handler

    story_class.txt

    story_class

    lib

    common.py

    common

    log

    log.log

    
    

    README.TXT

    readme

    二:代码

    bin

    start.py

    # 用于存放启动文件
    
    import os  # 导入os模块
    import sys  # 导入sys模块
    
    # 将项目的根目录,添加到sys.path中
    sys.path.append(
        os.path.dirname(os.path.dirname(__file__))
    )
    
    from core import src  # 导入core中的src模块
    
    if __name__ == '__main__':
        src.run()
    

    conf

    settings.py

    # 用于存放配置文件
    
    import os
    
    # 获取项目根目录Novel - 1的根目录
    BASE_PATH = os.path.dirname(os.path.dirname(__file__))
    
    # 获取db目录的路径
    DB_PATH = os.path.join(BASE_PATH, 'db')
    
    # 获取db.txt的根目录
    DB_TXT_PATH = os.path.join(DB_PATH, 'db.txt')
    
    # story_class文件目录路径
    STORY_PATH = os.path.join(DB_PATH, 'story_class.txt')
    
    # 小说存放目录
    FICTION_DIR = os.path.join(DB_PATH, 'fictions')
    
    # 日志文件的路径
    LOG_PATH = os.path.join(BASE_PATH, 'log', 'log.txt')
    

    core

    src.py

    # 用于存放核心代码
    
    import time
    from db import db_handler
    from lib import common
    
    # 定义login_user:若能进入该函数,证明该用户已经登录,还能获取当前用户名
    login_user = None
    
    
    # 0 注册功能
    def register():
        print('注册功能执行中...')
        while True:
            username = input('请输入用户名:').strip()
    
            # 1.先校验用户是否存在
            # 涉及数据的操作:调用查看数据的功能:select
            # 给select函数传入当前输入的用户名,判断该用户是否存在
            user_data = db_handler.select(username)
    
            # 2.若存在,则让用户重新输入
            if user_data:
                print('当前用户已存在,请重新输入!')
                continue
    
            password = input('请输入密码:').strip()
            re_password = input('请确认密码:').strip()
    
            # 3.检测两次输入的密码是否一致
            if password == re_password:
    
                # 4.将当前用户的数据写入到文件中
                db_handler.save(username, password)
                print(f'用户[{username}]注册成功!')
                break
    
            else:
                print('两次密码不一致,请重新输入!')
    
    
    # 1 登录功能
    def login():
        print('登录功能执行中...')
        while True:
            username = input('请输入用户名:').strip()
    
            # 1.查看当前用户是否存在
            user_data = db_handler.select(username)
    
            # 2.若不存在,则让用户重新输入
            if not user_data:
                print('该用户不存在,请重新输入!')
                continue
    
            password = input('请输入密码:').strip()
    
            # 3.校验用户输入的密码是否与db.txt中的密码一致
            if password == user_data[1]:
    
                # 4.用户登录后,记录登录状态
                global login_user
                login_user = username
    
                print(f'用户[{username}]登录成功!')
                break
    
            else:
                print('密码错误,登录失败!')
    
    
    # 2 充值功能
    @common.login_auth
    def recharge():
        print('充值功能执行中...')
        while True:
            # 1.让用户输入充值的金额
            balance = input('请输入要充值的金额:').strip()
    
            # 2.判断用户输入的是否是数字
            if not balance.isdigit():
                print('请输入数字!')
                continue
    
            balance = int(balance)  # 将字符串类型 转换成 数字类型
    
            # 3.修改当前用户的金额
            # 3.1.获取当前用户数据
            user, pwd, bal = db_handler.select(login_user)  # [user, pwd, bal]
    
            # 3.2.先获取用户“修改前”的数据
            old_data = f'{user}:{pwd}:{bal}'
    
            # 3.3.修改当前用户金额,做加钱操作
            bal = int(bal)
            bal += balance  # bal是取出来的数据,balance是用户输入的要增加的数据
    
            # 3.4.拼接“修改后”的用户数据
            new_data = f'{user}:{pwd}:{bal}'
    
            # 3.5.调用修改数据的功能
            db_handler.update(old_data, new_data)
            print(f'当前用户:[{login_user}]充值金额:[{balance}]元,成功!')
    
            # ending:做充值日志记录
            now_time = time.strftime('%Y-%m-%d %X')
            log_data = f'时间:{now_time} 用户名:{login_user} 充值金额:{balance}'
            print(log_data)
            common.append_log(log_data)  # 将日志信息添加进去
            break
    
    
    # 3 小说阅读功能
    @common.login_auth
    def reader():
        print('小说阅读功能执行中...')
        '''
        1.写该功能之前,现将小说数据,存放在story_class.txt文件中
        2.现将story_class.txt文件中的数据读取出来,然后解析成字典类型
        '''
        story_dic = db_handler.get_all_story()
    
        # 判断story_class.txt文件中是否有小说数据
        if not story_dic:
            print('没有小说,请联系管理员!')
            return
    
        while True:
            # 1.打印小说的种类选择信息
            print('''
            ======= Welcome To Index Page =======
                    0 起源系列
                    1 重生系列
                    2 轮回系列
            ''')
    
            # 2.让用户输入小说类型编号
            choice1 = input('请输入小说类型编号:').strip()
    
            # 3.判断当前用户选择的编号是否存在
            # 若不存在,就重新输入
            if choice1 not in story_dic:
                print('输入有误,请重新输入!')
                continue
    
            # 4.获取当前小说类型中的所有小说
            fiction_dic = story_dic.get(choice1)
    
            # 5.打印当前类型的所有小说
            for number, fiction_list in fiction_dic.items():
                name, price = fiction_list
                print(f'小说编号:[{number}]  小说名字:[{name}]  小说价格:[{price}]')
    
            # 6.让用户选择需要购买的小说
            while True:
                choice2 = input('请输入要购买的小说编号:').strip()
                if choice2 not in fiction_dic:
                    print('输入有误,请重新输入!')
                    continue
    
                name, price = fiction_dic.get(choice2)
    
                # 7.让用户输入y,选择是否要购买商品
                choice3 = input(f'当前选择的小说名为:[{name}],商品单价为:[{price}],请输入 y 购买').strip()
    
                # 8.判断用户输入的是否是 y
                if choice3 == 'y':
    
                    # 9.校验当前用户的余额是否大于小说单价
                    # 9.1.获取当前用户的金额
                    user, pwd, bal = db_handler.select(login_user)
    
                    # 9.2.判断金额
                    bal = int(bal)
                    price = int(price)
    
                    if bal < price:
                        print('穷逼,回家种田去吧!')
                        break
    
                    # 10.如果余额充足,就开始扣费
                    # 10.1.拼接用户 “修改前” 的数据
                    old_data = f'{user}:{pwd}:{bal}'
    
                    # 10.2.开始扣费
                    bal -= price  # bal是用户的原来余额,price是要扣去的小说的价格
    
                    # 10.3.拼接用户 “修改后” 的数据
                    new_data = f'{user}:{pwd}:{bal}'
                    db_handler.update(old_data, new_data)
    
                    print('当前小说购买成功,自动打开小说进行阅读~')
    
                    # 11.调用获取小说的详情信息
                    fiction_data = db_handler.show_fiction_data(name)
                    print(f'''
                    ======= 当前小说数据如下 =======
                    {fiction_data}
                    ''')
    
                    # 12.记录购买成功的日志
                    now_time = time.strftime('%Y-%m-%d %X')
                    log_data = f'时间:[{now_time}] 用户名:[{login_user}] 消费金额:[{price}]'
                    print(log_data)
                    common.append_log(log_data)
                    break
    
    
    # 函数字典
    func_dic = {
        '0': register,
        '1': login,
        '2': recharge,
        '3': reader,  # 这个逗号可有可无,加了也没关系
    }
    
    
    # 启动函数
    def run():
        print('启动ing...')
        while True:
            print('''
            ======= 小说阅读器欢迎您 =======
                    0 账号注册
                    1 账号登录
                    2 充值功能
                    3 阅读小说
            ''')
    
            choice = input('请输入功能编号(温馨提示[输入q退出]:').strip()
    
            if choice == 'q':
                break
    
            #  判断用户输入的编号是否在函数字典中
            if choice not in func_dic:
                print('当前编号有误,请重新输入!')
                continue
    
            func_dic.get(choice)()
    

    db

    foctions

    egon流浪记 - 序曲.txt

    egon从小就是一个孤儿
    egon从小就是一个孤儿
    egon从小就是一个孤儿
    egon从小就是一个孤儿
    egon从小就是一个孤儿
    

    成长之路 - 起源.txt

    egon历经千辛万苦,终于活了下来
    egon历经千辛万苦,终于活了下来
    egon历经千辛万苦,终于活了下来
    egon历经千辛万苦,终于活了下来
    egon历经千辛万苦,终于活了下来
    

    绿色的光 - 毁灭.txt

    egon头上闪耀着奇异的光芒
    egon头上闪耀着奇异的光芒
    egon头上闪耀着奇异的光芒
    egon头上闪耀着奇异的光芒
    egon头上闪耀着奇异的光芒
    

    egon再临 - 重生.txt

    egon,复活了
    egon,复活了
    egon,复活了
    egon,复活了
    egon,复活了
    

    父子局 - 轮回.txt

    Alex和egon相爱相杀
    Alex和egon相爱相杀
    Alex和egon相爱相杀
    Alex和egon相爱相杀
    Alex和egon相爱相杀
    

    egon养成攻略 - 终章.txt

    把不用的egon撒上鸡蛋液,裹上面包糠,隔壁小孩馋哭了
    把不用的egon撒上鸡蛋液,裹上面包糠,隔壁小孩馋哭了
    把不用的egon撒上鸡蛋液,裹上面包糠,隔壁小孩馋哭了
    把不用的egon撒上鸡蛋液,裹上面包糠,隔壁小孩馋哭了
    把不用的egon撒上鸡蛋液,裹上面包糠,隔壁小孩馋哭了
    

    db.txt

    
    

    db_handler

    # 用于存放数据操作代码
    
    from conf import settings
    import os
    
    
    # 查看数据
    def select(username):
        # 接受用户名,若存在,就返回当前用户的所有数据;若不存在,就返回None
        with open(settings.DB_TXT_PATH, mode='rt', encoding='UTF-8') as f:
            # 获取db.txt文件中的每一行数据
            for line in f:
                # 在每一行中,判断接收过来的用户名是否存在于db.txt文件中
                if username in line:
                    # 若用户存在,则在当前行中,提取该用户的所有数据
                    user_data = line.strip().split(':')  # 用split将:切分
                    # 将当前数据,返回给调用者
                    return user_data
    
    
    # 保存数据
    def save(username, password, balance=0):
        '''
        :param username: 注册的用户名
        :param password: 注册的密码
        :param balance: 注册时,默认余额为0
        :return:
        '''
        with open(settings.DB_TXT_PATH, mode='at', encoding='UTF-8') as f:
            # 将注册的信息添加到db.txt中
            f.write(f'{username}:{password}:{balance}
    ')
    
    
    # 更新数据
    def update(old_data, new_data):
        '''
        :param old_data: 用户原来的数据
        :param new_data: 用户的新数据
        :return:
        '''
        # 1.拼接新的文件路径
        new_path = os.path.join(
            settings.DB_PATH, 'new.txt'
        )
        # 2.读取db.txt文件中的数据 进行修改,写入到新文件new.txt中,再更换为db.txt文件名
        with open(settings.DB_TXT_PATH, mode='rt', encoding='UTF-8') as r_f, 
                open(new_path, mode='wt', encoding='UTF-8') as w_f:
            # 2.1.新旧数据替换    尽量让代码更加简洁
            all_user_data = r_f.read()
            all_user_data = all_user_data.replace(old_data, new_data)
    
            # 2.2.将新的数据写入到新文件new.txt中
            w_f.write(all_user_data)
    
        # 3.文件名的修改  os.remove()可以不写,因为原来的db.txt会被覆盖掉
        os.replace(new_path, settings.DB_TXT_PATH)
    
    
    # 获取小说字典数据
    def get_all_story():
        with open(settings.STORY_PATH, mode='rt', encoding='UTF-8') as f:
            story_dic = eval(f.read())
            return story_dic
    
    
    # 查看单本小说
    def show_fiction_data(fiction_name):
        # 获取小说的路径
        fiction_path = os.path.join(
            settings.FICTION_DIR, fiction_name
        )
    
        # 打开文件,获取文件数据,并返回给用户
        with open(fiction_path, mode='rt', encoding='UTF-8') as f:
            fiction_data = f.read()
    
            return fiction_data
    

    story_class.txt

    {
        "0":{
            "0":["egon流浪记 - 序曲.txt",50],
            "1":["成长之路 - 起源.txt",100]
        },
        "1":{
            "0":["绿色的光 - 毁灭.txt",200],
            "1":["egon再临 - 重生.txt",400]
        },
        "2":{
            "0":["E&A父子局 - 轮回.txt",500],
            "1":["egon养老攻略 - 终章.txt",1000]
        },
    
    }
    

    lib

    common.py

    # 用于存放公共的功能
    
    from conf import settings
    
    
    # 登录认证装饰器login_auth
    def login_auth(func):
        # 解决问题:循环导入问题
        from core import src
    
        def inner(*args, **kwargs):
            if src.login_user:
                res = func(*args, **kwargs)
                return res
            else:
                print('未登录,不允许使用其他功能,请先登录!')
                src.login()
    
        return inner
    
    
    # 记录日志,应该放在公共功能中
    def append_log(log_data):
        # 写入日志数据
        with open(settings.LOG_PATH, mode='at', encoding='UTF-8') as f:
            f.write(log_data + '
    ')
    

    log

    log.log

    
    

    README.TXT

    # 软件的使用规范
    
    一 软件开发目录规范
    
        - api   存放接口文件,接口主要用于为业务逻辑提供数据操作
            - api.py --> 应用程序编程接口
    
        - bin   整个项目的启动文件放置在这个文件夹中
            - start.py --> 启动软件入口
    
        - conf  整个项目的配置文件放置在这个文件夹
            - settings.py   配置文件
                - 比如存放一些固定的路径
    
        - core  整个项目的核心文件
            - src.py 核心业务逻辑代码
    
        - db    用于存放数据文件与操作数据的代码文件
            - db_file ---> db.txt ...
            - db_handler.py ---> 操作数据的代码
    
        - lib   项目的第三方包,共享的一些库
            - common: 存放公共的功能
                - 比如存放 装饰器
    
        - log   用于存放项目的日志文件
            - log.txt  存放日志的文件
    
        - README.TXT    整个项目的说明文件,项目需求和大致流程,相当于产品说明书
    
    
    二 一个项目开发前,有一份开发文档
    
        项目: 编写小说阅读程序实现下属功能
    
            # 一:程序运行开始时显示
                0 账号注册
                1 账号登录
                2 充值功能
                3 阅读小说
    
            # 二: 针对文件db.txt,内容格式为:"用户名:密码:金额",完成下述功能
                2.1、账号注册
                2.2、账号登录
                2.3、充值功能
    
            # 三:文件story_class.txt存放类别与小说文件路径,如下,读出来后可用eval反解出字典
                {
                    "0":{
                        "0":["egon流浪记 - 序曲.txt",50],
                        "1":["成长之路 - 起源.txt",100]
                    },
                    "1":{
                        "0":["绿色的光 - 毁灭.txt",200],
                        "1":["egon再临 - 重生.txt",400]
                    },
                    "2":{
                        "0":["父子局 - 轮回.txt",500],
                        "1":["egon养成攻略 - 终章.txt",1000]
                    },
                }
    
                3.1、用户登录成功后显示如下内容,根据用户选择,显示对应品类的小说编号、小说名字、以及小说的价格
                """
                0 起源系列
                1 重生系列
                2 轮回系列
                """
    
                3.2、用户输入具体的小说编号,提示是否付费,用户输入y确定后,
                     扣费并显示小说内容,如果余额不足则提示余额不足
    
            # 四:为功能2.2、3.1、3.2编写认证功能装饰器,要求必须登录后才能执行操作
    
            # 五:为功能2.2、3.2编写记录日志的装饰器,日志格式为:"时间 用户名 操作(充值or消费) 金额"
    
    
            # 附加:
            # 可以拓展作者模块,作者可以上传自己的作品
    
  • 相关阅读:
    嵌入式linux驱动开发之点亮led(驱动编程思想之初体验)
    嵌入式Linux驱动开发之helloword心得
    PJMEDIA之录音器的使用(capture sound to avi file)
    PJMEID学习之视频的捕捉与播放
    PJSIP-PJMEDIA【使用pjmedia 播放wav格式的音乐】
    PJSIP-PJLIB-Socket
    PJSIP-PJLIB(samples) (the usage of the pjlib lib) (eg:string/I/O)
    Start with PJSIP on windows
    Android实际开发之网络请求组件的封装(OkHttp为核心)
    Android实际开发中的首页框架搭建(二、首页框架实现)
  • 原文地址:https://www.cnblogs.com/xuexianqi/p/12600935.html
Copyright © 2011-2022 走看看