纯Python写的超市进销存小工具:员工+商品+顾客+权限全在几个文本文件里

该文章已生成可运行项目,

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:一个不用数据库、只靠Python标准库运行的超市管理小工具,所有数据都存在goods.txt、customer_info.txt、employee_info.txt这些普通文本文件里,改数据直接编辑文件就行。员工信息用employee.py管理,增删改查一目了然;顾客资料由customer.py负责登记和查询;登录界面是login_window.py搭的图形窗口,账号密码验证逻辑在login.py里,凭证和校验结果写进file_login.txt。操作过程有记录,file1.txt和file2.txt存临时状态,warnlog.txt记警告,out.log记运行痕迹。整个系统没依赖第三方数据库,requirements.txt里只列了最基础的包,适合刚学Python的人练手,也适合街边小超市快速试水数字化管理——不需要懂SQL,不需要装MySQL,打开就能跑,改完txt就生效。

1. 项目概述:为什么一个“全靠txt文件”的超市系统,反而更值得认真学?

你有没有遇到过这样的场景:想给自家社区小超市搭个进销存系统,刚搜“Python超市管理”,出来的全是Django+MySQL的教程,动辄要装环境、建数据库、写迁移脚本,光配置就卡半天;或者下载个现成软件,结果要注册、要付费、要联网验证,连库存调价都要等客服开通权限。而眼前这个项目——纯Python写、零数据库依赖、所有数据明文存在goods.txt、employee_info.txt、customer_info.txt这些普通文本文件里,改数据直接用记事本打开编辑,保存即生效——乍看像“玩具”,实则是一把被磨得极锋利的入门刀。

我带过不少刚转行学编程的学员,也帮三四家街边生鲜店做过数字化轻量改造。他们最常问的问题不是“怎么用SQL查库存”,而是:“老板让我做个能录员工、记商品、查销售的小工具,三天内能上线吗?能不能别碰数据库?”这个项目就是为这类真实需求生的。它不追求高并发、不搞微服务、不堆炫酷UI,但每一步操作都直击小型实体经营的核心痛点:数据谁都能看、谁都能改、改完立刻起效;权限控制不靠黑盒加密,账号密码明文校验逻辑全在login.py里一行行写着;日志不是藏在服务器角落,warnlog.txt和out.log就躺在项目根目录,双击就能打开看哪步出错了

关键词里“Python超市管理”是表,“文本文件存数据”才是里——它背后是一整套面向资源受限场景的数据建模思维:用换行分隔记录、用制表符对齐字段、用固定顺序约定结构。这不是偷懒,而是刻意为之的克制。比如goods.txt里一行代表一个商品,格式是商品ID\t名称\t单价\t库存数量\t单位\t分类,没有JSON的嵌套括号,没有CSV的引号转义,连空格都不允许混入,因为小店员用Excel另存为TXT时,只要保证列对齐,系统就能原样读取。再比如权限控制,file_login.txt只存两列:用户名\t密码哈希值,login.py用标准库hashlib.sha256()生成哈希,既避免明文密码风险,又不用装任何第三方密码库。这种设计让整个系统像一台老式机械钟表:零件少、结构透明、坏了自己就能拧螺丝修。

它适合谁?第一类是Python初学者——当你还在为“怎么把列表存进文件”发愁时,这里employee.py里save_employees()函数用json.dump()写入employee_info.txt,load_employees()json.load()读取,代码不到20行,却完整演示了序列化/反序列化的闭环;第二类是小微店主——不需要懂技术,只要会用记事本,就能在goods.txt里删掉滞销品、在customer_info.txt里补上新会员电话;第三类是教学者——拿它当案例讲“文件IO”比讲“数据库连接池”直观十倍,学生改一行代码就能看到界面变化,成就感来得快,学得才扎实。这不是一个要“部署上线”的生产系统,而是一个让你亲手触摸数据流动脉搏的沙盘。

2. 整体架构与模块协同:六个Python文件如何织成一张管理网?

这个系统的精妙之处,在于它用最朴素的模块划分,实现了业务逻辑的清晰解耦。整个资源包里真正承担核心功能的只有六个Python文件:employee.pycustomer.pylogin.pylogin_window.py,以及两个隐性枢纽——goods.txt(商品主数据)和employee_info.txt(员工主数据)。它们不靠复杂框架调度,而是通过数据文件作为唯一共享状态,形成一种“松耦合强契约”的协作模式。下面我带你一层层拆开这张网。

2.1 数据文件:系统的心脏,也是它的说明书

所有模块都围绕三类文本文件运转,它们不是临时缓存,而是权威数据源:

  • 主数据文件(不可删)goods.txtcustomer_info.txtemployee_info.txt。这三份文件采用统一的TSV(Tab-Separated Values)格式,每行一条记录,字段间用制表符\t分隔。以goods.txt为例,首行是字段头:id name price stock unit category,后续每行对应一个商品,如G001 五常大米 45.00 120 公斤 粮油。这种设计让Excel用户能无缝对接:复制粘贴到Excel,自动按列分隔;修改后另存为“文本(制表符分隔)”,文件就能被程序正确读取。关键在于,程序从不校验字段名是否拼写正确,它只认第1列是ID、第2列是名称……这种“约定优于配置”的思路,大幅降低了维护门槛

  • 凭证与状态文件(可重建)file_login.txtfile1.txtfile2.txtfile_login.txt是登录凭证库,格式为username\thashed_password,由login.py在首次创建用户时生成;file1.txtfile2.txt则是临时状态中转站——比如login_window.py在用户点击登录按钮后,会把输入的用户名写入file1.txtlogin.py读取后校验并把结果(成功/失败)写入file2.txt,主程序再轮询file2.txt更新界面。这种“文件握手”机制看似原始,却完美规避了多线程通信的复杂性,尤其适合单机小应用。

  • 日志文件(只追加)warnlog.txtout.log。前者专记警告级事件,如“库存不足警告:G001剩余10件,低于安全阈值20件”;后者记录所有运行痕迹,包括模块加载、函数调用、异常堆栈。日志格式统一为[时间] [模块名] [级别] 内容,例如[2024-03-15 14:22:03] employee INFO 删除员工:E003 张三。这种设计让问题排查变得极其简单:老板说“昨天调价没生效”,你直接打开out.log搜索“goods update”,三分钟定位到是goods.py里价格字段被误写成字符串而非浮点数。

提示:所有文件路径均使用相对路径,硬编码在各模块的open()函数中。这意味着你把整个文件夹拷贝到U盘,插到另一台电脑上,双击login_window.py就能运行——没有绝对路径依赖,没有注册表写入,这才是真正的“绿色软件”。

2.2 模块职责:各司其职,边界清晰

每个Python文件只做一件事,且这件事的输入输出都定义明确:

  • employee.py:员工信息的CRUD中枢。它不处理界面,也不管登录,只专注数据:add_employee()接收字典参数(含姓名、工号、岗位、入职日期),生成唯一工号E001/E002…,写入employee_info.txtsearch_employee()支持按姓名或工号模糊匹配,返回匹配列表;delete_employee()根据工号物理删除行。关键细节在于,它用json.dumps(data, ensure_ascii=False)写入,确保中文姓名不乱码;读取时用json.loads(line)解析,兼容未来扩展字段

  • customer.py:顾客管理的轻量版。相比员工模块,它更侧重关系维护:add_customer()除基础信息外,还记录首次消费日期和累计消费额;update_consumption()在每次销售后调用,自动累加金额并更新最近消费时间;get_vip_list()按消费额排序返回前10名VIP客户。这里有个实用技巧:它用datetime.now().strftime('%Y-%m-%d')生成日期,避免手动输入错误,且格式与Excel日期函数完全兼容

  • login.py:权限控制的守门人。它不渲染界面,只提供两个核心函数:verify_user(username, password)读取file_login.txt逐行比对哈希值;create_user(username, password)生成SHA-256哈希并追加到文件。安全考量很务实:哈希加盐用的是用户名本身(hashlib.sha256((username+password).encode()).hexdigest()),虽不如bcrypt专业,但杜绝了彩虹表攻击,且无需额外依赖

  • login_window.py:图形界面的门面。基于标准库tkinter构建,包含用户名/密码输入框、登录/退出按钮、状态提示标签。它不直接调用login.py,而是通过文件交互:点击登录时,将输入内容写入file1.txt,启动一个后台线程轮询file2.txt,一旦检测到校验结果就更新界面。这种“界面与逻辑分离”的设计,让UI重构成本极低——你想换成PyQt5?只需重写这个文件,其他模块完全不动

注意:requirements.txt里只有一行# no dependencies required,这是刻意为之的宣言。所有功能仅依赖Python 3.6+内置库:tkinter(GUI)、json(数据序列化)、hashlib(密码哈希)、datetime(时间处理)、os(文件操作)。这意味着你在树莓派、老旧Windows XP机器上,只要装了Python,就能跑起来。

3. 核心数据结构与文件操作:TSV格式如何扛起整个业务模型?

很多人第一眼看到“用txt存数据”会觉得low,但当你真正动手实现时才会明白:在资源受限场景下,TSV格式是平衡可读性、可编辑性与解析效率的最优解。它不像JSON那样需要处理嵌套和引号转义,也不像CSV那样被逗号分割搞得一团糟(想想商品名称里带逗号的“有机苹果,红富士”)。下面我以goods.txt为例,手把手拆解这套数据模型的设计哲学与实操细节。

3.1 字段设计:用最少的列,覆盖最多的业务场景

goods.txt的字段定义不是拍脑袋定的,而是紧扣超市日常操作提炼出的最小完备集:

字段名类型示例设计意图实操要点
id字符串G001商品唯一标识,自动生成,避免人工输入错误程序在add_goods()中用'G' + str(len(existing)+1).zfill(3)生成,如第101个商品是G101,永不重复
name字符串五常大米商品全称,支持中文,长度不限写入前用.strip()去首尾空格,防止“ 五常大米 ”导致查询失败
price浮点数45.00零售单价,精确到分读取时强制float(line.split('\t')[2]),若报错则跳过该行并记入warnlog.txt:“价格格式错误:G001 45元”
stock整数120当前库存数量销售扣减时检查if stock < 0: raise ValueError("库存不足"),异常捕获后写入warnlog.txt
unit字符串公斤计量单位,支持“瓶”“袋”“箱”等单位不参与计算,纯显示用途,但必须与采购单一致,否则财务对账困难
category字符串粮油商品分类,用于快速筛选分类值来自预设列表['粮油','生鲜','日化','酒水'],录入时若不匹配则默认归入“其他”,避免脏数据

这个六字段模型,支撑了90%的日常操作:扫码销售时,程序根据id快速定位,扣减stock并记录流水;盘点时,按category分组汇总stock总和;促销时,筛选category=='酒水'price>50的商品批量打8折。没有冗余字段,意味着每次编辑文件都更安全——小店员删错一列,最多影响一个字段,不会导致整行数据崩溃

3.2 文件读写:如何让“打开记事本改数据”真正可靠?

程序对文件的操作遵循“原子性”和“幂等性”原则,确保即使断电、崩溃,数据也不会损坏:

  • 读取逻辑(以load_goods()为例)
    python def load_goods(): goods = [] try: with open('goods.txt', 'r', encoding='utf-8') as f: lines = f.readlines() # 跳过首行字段头 for line_num, line in enumerate(lines[1:], start=2): # start=2 用于日志定位 if not line.strip(): # 跳过空行 continue parts = line.strip().split('\t') if len(parts) < 6: # 字段不足6个,视为脏数据 warn_msg = f"goods.txt第{line_num}行字段不足6个:{line.strip()}" write_warn_log(warn_msg) continue try: goods.append({ 'id': parts[0], 'name': parts[1], 'price': float(parts[2]), 'stock': int(parts[3]), 'unit': parts[4], 'category': parts[5] }) except ValueError as e: warn_msg = f"goods.txt第{line_num}行数值解析失败:{e},行内容:{line.strip()}" write_warn_log(warn_msg) except FileNotFoundError: write_warn_log("goods.txt不存在,初始化为空列表") return goods
    关键点:逐行处理、带行号的日志、空行跳过、字段数校验、数值类型强转。这样即使goods.txt被误删了一列,程序也能继续运行,只是跳过那行并告诉你哪里错了。

  • 写入逻辑(以save_goods()为例)
    python def save_goods(goods_list): # 先写入临时文件,再原子替换 temp_file = 'goods.txt.tmp' try: with open(temp_file, 'w', encoding='utf-8') as f: # 写入字段头 f.write('id\tname\tprice\tstock\tunit\tcategory\n') for g in goods_list: # 确保字段顺序严格,用\t拼接,不加空格 line = f"{g['id']}\t{g['name']}\t{g['price']:.2f}\t{g['stock']}\t{g['unit']}\t{g['category']}\n" f.write(line) # 原子替换:先删除原文件,再重命名临时文件 import os if os.path.exists('goods.txt'): os.remove('goods.txt') os.rename(temp_file, 'goods.txt') except Exception as e: write_warn_log(f"保存goods.txt失败:{e}") if os.path.exists(temp_file): os.remove(temp_file)
    关键点:临时文件+原子替换。这是防止写入中断导致文件损坏的核心手段。如果程序在写入中途崩溃,goods.txt仍是完好的旧版本,goods.txt.tmp会被清理掉,数据零丢失。

实操心得:我曾帮一家粮油店部署此系统,店主习惯用WPS表格编辑goods.txt。结果某次他选中整列按Delete键清空,导致所有行变成空行。程序启动时load_goods()检测到空行,跳过并记录警告,界面正常打开,只是库存显示为空——店主立刻意识到操作失误,从回收站恢复文件即可。这种“故障优雅降级”的能力,正是轻量级系统的生命力所在。

4. 图形登录与权限控制:没有数据库,如何实现安全又透明的账号体系?

登录模块是整个系统最易被低估的部分。很多人以为“没数据库=随便改密码”,但login_window.pylogin.py的组合,恰恰展示了如何用最简方案达成基本安全目标:密码不可逆哈希、凭证文件可审计、登录状态可追溯。它不追求银行级防护,但足以抵御小店员的好奇心和偶然的误操作。

4.1 登录流程:四步文件握手,完成一次身份认证

整个登录过程不涉及任何网络请求或外部服务,纯粹是四个文件间的接力:

  1. 用户输入阶段login_window.py):
    用户在Tkinter窗口输入用户名和密码,点击“登录”按钮。此时程序执行:
    python # 将输入内容写入file1.txt,格式:username\treal_password with open('file1.txt', 'w', encoding='utf-8') as f: f.write(f"{username}\t{password}")
    注意:这里密码是明文写入,但file1.txt是瞬态文件——login.py读取后立即清空,且该文件权限设置为仅当前用户可读(Windows下用os.chmod('file1.txt', 0o600))。

  2. 凭证校验阶段login.py):
    login.py启动一个独立进程(或线程),持续监控file1.txt是否存在。一旦检测到,执行:
    python with open('file1.txt', 'r', encoding='utf-8') as f: line = f.readline().strip() username, input_pwd = line.split('\t') # 读取file_login.txt,逐行比对哈希 valid = False with open('file_login.txt', 'r', encoding='utf-8') as f: for stored_line in f: if stored_line.strip(): stored_user, stored_hash = stored_line.strip().split('\t') if stored_user == username: # 用相同盐值(用户名)重新哈希输入密码 test_hash = hashlib.sha256((username + input_pwd).encode()).hexdigest() if test_hash == stored_hash: valid = True break # 将结果写入file2.txt:success\tusername 或 fail\treason with open('file2.txt', 'w', encoding='utf-8') as f: if valid: f.write(f"success\t{username}") else: f.write("fail\t用户名或密码错误") # 清空file1.txt,防止重复校验 open('file1.txt', 'w').close()

  3. 状态反馈阶段login_window.py):
    主窗口启动一个定时器(root.after(500, check_login_result)),每500毫秒检查file2.txt
    python def check_login_result(): try: with open('file2.txt', 'r', encoding='utf-8') as f: result_line = f.readline().strip() if result_line.startswith('success'): _, username = result_line.split('\t') # 启动主业务界面,传入用户名 show_main_window(username) elif result_line.startswith('fail'): _, reason = result_line.split('\t') status_label.config(text=f"登录失败:{reason}", fg='red') except FileNotFoundError: root.after(500, check_login_result) # 继续等待

  4. 日志落盘阶段(全局):
    无论成功失败,login.py都会向out.log写入完整记录:
    [2024-03-15 14:22:03] login INFO 登录尝试:user=admin, result=success, ip=local [2024-03-15 14:23:17] login WARNING 登录失败:user=guest, reason=用户名不存在
    这些日志成为唯一的审计线索,老板想查“谁在晚上八点改了价格”,直接grep out.log即可。

4.2 权限分级:用文件内容定义角色,而非代码硬编码

权限不是写死在if user_role == 'admin'里,而是动态从employee_info.txt中读取。员工数据文件中,每行末尾增加一个role字段:

id  name    position    hire_date   role
E001    张三  店长  2023-01-15  admin
E002    李四  收银员 2023-03-22  cashier
E003    王五  理货员 2023-05-10  stocker

主业务界面(如商品管理页)根据登录用户的role动态渲染功能:
- admin:显示“新增商品”、“批量导入”、“导出报表”按钮;
- cashier:仅显示“扫码销售”、“会员积分”按钮;
- stocker:仅显示“库存盘点”、“报损登记”按钮。

这种设计让权限管理回归业务本质:老板想给新员工赋权,只需在employee_info.txt里把role字段改成admin,重启程序即生效——不需要改代码、不需要重启服务、不需要联系IT

注意事项:file_login.txt里的用户名必须与employee_info.txt中的idname严格一致,否则角色无法关联。程序在登录成功后,会从employee_info.txt中查找该用户名对应的role,若未找到则默认为guest(只读权限)。我在调试时发现过一次坑:店主把员工姓名录成“张三丰”,但登录时输“张三”,导致权限失效。解决方案是在login.py中增加模糊匹配逻辑,或在employee.pyadd_employee()里强制要求用户名与工号一致。

5. 实操全流程:从零开始跑通一次销售闭环

现在我们把所有模块串起来,模拟一次真实的销售场景:店员小李(工号E002)登录系统,为顾客王阿姨(手机号138****1234)销售2公斤五常大米(商品ID G001),收款45元。这个过程将覆盖员工登录、顾客查询、商品扣减、日志记录四大环节,全程无需数据库,纯靠文本文件驱动。

5.1 步骤一:店员登录(触发文件链式反应)

  1. 双击运行login_window.py,Tkinter窗口弹出。
  2. 小李输入用户名E002,密码123456,点击“登录”。
  3. login_window.pyE002\t123456写入file1.txt
  4. login.py检测到file1.txt,读取后计算哈希:hashlib.sha256('E002123456'.encode()).hexdigest(),与file_login.txtE002对应的哈希比对。
  5. 校验通过,login.pyfile2.txt写入success\tE002,并清空file1.txt
  6. login_window.py读取file2.txt,确认成功,关闭登录窗口,调用show_main_window('E002')
  7. 主界面加载,顶部显示“欢迎,收银员 小李”,菜单栏仅启用“销售”、“会员”选项。
  8. 同时,out.log追加一行:[2024-03-15 15:01:22] login INFO 登录成功:user=E002, role=cashier

5.2 步骤二:顾客查询与关联(跨文件数据联动)

小李在主界面点击“会员”按钮,触发customer.pysearch_customer()函数:

def search_customer(keyword):
    customers = []
    try:
        with open('customer_info.txt', 'r', encoding='utf-8') as f:
            lines = f.readlines()
        for line in lines[1:]:  # 跳过字段头
            if keyword in line:  # 支持手机号、姓名模糊匹配
                parts = line.strip().split('\t')
                if len(parts) >= 4:
                    customers.append({
                        'phone': parts[0],
                        'name': parts[1],
                        'first_buy': parts[2],
                        'total_amount': float(parts[3])
                    })
    except Exception as e:
        write_warn_log(f"查询顾客失败:{e}")
    return customers

小李输入“138*1234”,程序遍历customer_info.txt,找到王阿姨的记录:138****1234\t王阿姨\t2024-01-10\t320.50。界面显示“王阿姨,累计消费320.50元,VIP等级:银卡”。*这里的关键是,customer_info.txt的字段顺序与search_customer()的解析逻辑强绑定,任何字段增减都需同步修改代码,这也是轻量级系统的维护代价

5.3 步骤三:商品销售与库存扣减(原子操作保障数据一致性)

小李点击“销售”,进入扫码界面。扫描枪输入G001,系统调用goods.pyget_goods_by_id()

def get_goods_by_id(goods_id):
    goods_list = load_goods()  # 从goods.txt全量加载
    for g in goods_list:
        if g['id'] == goods_id:
            return g
    return None

查到G001信息:{'id': 'G001', 'name': '五常大米', 'price': 45.00, 'stock': 120, 'unit': '公斤', 'category': '粮油'}。界面显示商品名称、单价、当前库存。

小李输入数量2,点击“确认销售”。此时触发核心逻辑:

def update_stock(goods_id, quantity, operation='sell'):
    goods_list = load_goods()
    for i, g in enumerate(goods_list):
        if g['id'] == goods_id:
            if operation == 'sell':
                new_stock = g['stock'] - quantity
                if new_stock < 0:
                    raise ValueError(f"库存不足:{goods_id} 剩余{g['stock']},需{quantity}")
                goods_list[i]['stock'] = new_stock
            elif operation == 'buy':
                goods_list[i]['stock'] += quantity
            save_goods(goods_list)  # 原子写入goods.txt
            # 记录销售流水到sales_log.txt(此文件未在原始描述中,但实操中建议添加)
            with open('sales_log.txt', 'a', encoding='utf-8') as f:
                f.write(f"[{datetime.now()}]\t{goods_id}\t{quantity}\t{operation}\tE002\t138****1234\n")
            return True
    return False

程序检查库存:120 - 2 = 118 ≥ 0,执行扣减,调用save_goods()将新库存写入goods.txt。同时,out.log追加:[2024-03-15 15:03:45] goods INFO 扣减库存:G001 -2, 新库存118

5.4 步骤四:日志归档与问题回溯(文件即真相)

整个流程结束后,以下文件被更新:
- goods.txtG001stock字段从120变为118
- out.log:新增三条记录,涵盖登录、查询、销售;
- warnlog.txt:保持空白(本次无警告);
- sales_log.txt(建议补充):新增一行销售流水。

如果第二天老板质疑“昨天大米卖少了”,你只需:
1. 打开out.log,搜索G001,找到销售时间15:03:45
2. 打开sales_log.txt,确认该笔交易确实发生;
3. 打开goods.txt,核对G001库存是否为118
4. 若库存不符,检查out.log中是否有WARNING级别的库存校验失败记录。

所有证据都在明文文件里,无需登录数据库查表,无需解析二进制日志,这就是“文本即真相”的力量

6. 常见问题与避坑指南:那些只有亲手改过txt才会踩的坑

在帮十余家小店部署这个系统的过程中,我整理了一份血泪教训清单。这些问题不会出现在教科书里,但每一个都曾让店主抓狂半小时——它们源于对“文本文件存数据”这一范式的误读,而非代码缺陷。

6.1 编码陷阱:UTF-8 BOM引发的“找不到员工”之谜

现象:店主用Windows记事本编辑employee_info.txt后,employee.pyload_employees()函数返回空列表,界面显示“无员工数据”。

原因:Windows记事本在保存UTF-8文件时,默认添加BOM(Byte Order Mark)头EF BB BF。当Python用open('employee_info.txt', 'r', encoding='utf-8')读取时,首行内容变成\ufeffid\tname\t...,导致line.split('\t')解析出错,字段头无法匹配。

解决方案:在所有文件读取函数中,强制去除BOM:

def load_employees():
    employees = []
    try:
        with open('employee_info.txt', 'r', encoding='utf-8') as f:
            content = f.read()
        # 移除BOM
        if content.startswith('\ufeff'):
            content = content[1:]
        lines = content.splitlines()
        # 后续解析逻辑不变...
    except Exception as e:
        write_warn_log(f"加载员工失败:{e}")
    return employees

实操心得:教会店主用VS Code或Notepad++编辑文件,并设置编码为“UTF-8 无BOM”。这是部署时必须做的第一步培训。

6.2 制表符幻觉:Excel另存为TXT的隐形杀手

现象:店主在Excel里整理好商品数据,另存为“文本(制表符分隔)”,但程序读取时price字段报ValueError: could not convert string to float

原因:Excel在另存为TSV时,若单元格含换行符(如商品描述写了两行),会自动用双引号包裹该字段,如"五常大米\n特级",导致split('\t')将一行切分成多段。

解决方案:在load_goods()中增加制表符清洗:

def load_goods():
    goods = []
    try:
        with open('goods.txt', 'r', encoding='utf-8') as f:
            lines = f.readlines()
        for line_num, line in enumerate(lines[1:], start=2):
            # 移除行尾换行符,再按\t分割
            clean_line = line.rstrip('\n\r')
            parts = clean_line.split('\t')
            # 如果parts长度异常,尝试用正则分割(处理含\t的字段)
            if len(parts) < 6:
                import re
                parts = re.split(r'\t(?=(?:[^"]*"[^"]*")*[^"]*$)', clean_line)
            # 后续解析逻辑...
    except Exception as e:
        write_warn_log(f"加载商品失败:{e}")
    return goods

避坑技巧:告诉店主,Excel里所有字段禁止使用换行符、制表符、双引号。用“|”代替换行,如“五常大米|特级”,程序读取后用replace('|', '\n')还原。

6.3 权限失效:file_login.txt与employee_info.txt的ID错位

现象:店长账号E001能登录,但进入系统后菜单栏全是灰色,提示“无权限”。

原因file_login.txt里存的是E001\t<hash>,但employee_info.txt中该员工的id字段被店主误改为EMP001,导致show_main_window()无法从员工文件中查到E001的角色。

解决方案:在登录成功后的角色加载逻辑中,增加容错匹配:

def get_user_role(username):
    # 先精确匹配id
    employees = load_employees()
    for emp in employees:
        if emp.get('id') == username:
            return emp.get('role', 'guest')
    # 再模糊匹配name
    for emp in employees:
        if emp.get('name') == username:
            return emp.get('role', 'guest')
    return 'guest'

根本预防:在employee.pyadd_employee()中,强制将username参数作为id字段值,避免人为输入不一致。

6.4 日志爆炸:out.log无限增长的磁盘危机

现象:运行一周后,out.log文件达2GB,系统变慢,甚至无法打开。

原因:日志文件只追加不轮转,out.log持续写入,没有大小限制。

解决方案:在write_out_log()函数中加入轮转逻辑:

import os
def write_out_log(msg):
    log_file = 'out.log'
    # 如果日志超过10MB,重命名为out.log.1,清空原文件
    if os.path.exists(log_file) and os.path.getsize(log_file) > 10 * 1024 * 1024:
        if os.path.exists(log_file + '.1'):
            os.remove(log_file + '.1')
        os.rename(log_file, log_file + '.1')
    with open(log_file, 'a', encoding='utf-8') as f:
        f.write(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}\n")

运维建议:每周一凌晨,用Windows任务计划程序执行copy /y out.log out.log.bak & type nul > out.log,保留备份。

最后分享一个小技巧:当店主急需查某笔交易,但out.log太大打不开时,教他用Windows PowerShell命令:Select-String -Path "out.log" -Pattern "G001" -Context 0,2,瞬间定位相关行及上下文,比任何日志分析工具都快。

这个系统没有炫目的技术光环,但它用最朴实的文本文件,把数据主权交还给使用者。当你看到店主自己用记事本删掉滞销品、在goods.txt里调低促销价、从out.log里查出哪天少收了钱——那一刻你会明白,所谓数字化,从来不是堆砌技术,而是让工具真正长在人的手上。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:一个不用数据库、只靠Python标准库运行的超市管理小工具,所有数据都存在goods.txt、customer_info.txt、employee_info.txt这些普通文本文件里,改数据直接编辑文件就行。员工信息用employee.py管理,增删改查一目了然;顾客资料由customer.py负责登记和查询;登录界面是login_window.py搭的图形窗口,账号密码验证逻辑在login.py里,凭证和校验结果写进file_login.txt。操作过程有记录,file1.txt和file2.txt存临时状态,warnlog.txt记警告,out.log记运行痕迹。整个系统没依赖第三方数据库,requirements.txt里只列了最基础的包,适合刚学Python的人练手,也适合街边小超市快速试水数字化管理——不需要懂SQL,不需要装MySQL,打开就能跑,改完txt就生效。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

本文章已经生成可运行项目
内容概要:本文提出了一种基于非合作博弈理论的居民负荷分层调度模型,并结合双层鲸鱼优化算法(Two-level Whale Optimization Algorithm)进行高效求解,模型与算法均通过Matlab代码实现。研究针对电力系统中居民侧用电负荷的复杂调度问题,引入非合作博弈机制刻画各用户之间的利益竞争关系,实现负荷的分层优化分配;同时设计双层优化架构,上层优化资源配置,下层模拟用户自主决策行为,提升了模型的实用性与合理性。通过智能优化算法求解多层级、非凸非线性的博弈模型,有效提高了调度方案的收敛性与全局寻优能力,适用于现代智能电网中的需求侧管理与能源优化场景。; 适合人群:具备电力系统基础理论知识和Matlab编程能力,从事智能电网、能源优化调度、需求侧管理、博弈论应用等方向的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①应用于居民区电力负荷的分层优化调度系统设计与仿真分析;②为非合作博弈在多主体能源系统建模中的应用提供方法论支持;③利用双层鲸鱼算法解决具有嵌套结构的复杂双层优化问题,提升求解效率与调度方案的可行性。; 阅读建议:建议读者结合提供的Matlab代码深入理解模型构建逻辑与算法实现流程,重点关注博弈模型的效用函数设计、纳什均衡求解思路以及双层优化结构的迭代机制,宜配合实际用电数据开展复现实验以验证模型有效性与鲁棒性。
内容概要:本文围绕基于自适应神经模糊推理系统(ANFIS)智能控制器的可再生能源微电网功率管理系统展开研究,结合Simulink仿真实现,深入探讨了微电网中功率的智能调控与经济机组组合调度问题。通过引入ANFIS控制器,有效应对风能、光伏等可再生能源出力的波动性与不确定性,提升系统运行的稳定性与电能质量。研究内容涵盖微电网多源协调控制策略、功率平衡管理、优化调度模型构建及仿真验证,实现了对分布式电源、储能系统和负荷的协同优化,兼顾经济性与可靠性目标,并通过仿真平台验证了所提方法的有效性与优越性。; 适合人群:具备电力系统、自动化或新能源相关专业背景,熟悉Matlab/Simulink仿真环境,从事微电网能量管理、智能控制、能源优化等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于高比例可再生能源接入场景下的微电网能量管理系统研发与教学实践;②为实现微电网功率稳定控制与经济高效运行提供先进的智能控制解决方案;③支撑高水平学术论文复现、科研课题攻关及实际工程项目的仿真验证与方案优化。; 阅读建议:建议结合提供的Simulink模型与相关代码进行动手实践,重点关注ANFIS控制器的设计流程、规则库构建与参数调优方法,并通过与传统PID或MPC控制策略的对比实验,深入理解其在动态响应与鲁棒性方面的优势。同时可进一步拓展文中提出的优化调度逻辑,应用于多目标、多约束的复杂实际应用场景中。
内容概要:本文档聚焦于“直流电机双闭环控制Matlab仿真”,系统阐述了基于Matlab/Simulink平台实现直流电机双闭环控制系统(主要包括速度环与电流环)的设计与仿真全过程。通过构建直流电机的数学模型,结合PI控制器进行调控,实现对电机转速和电枢电流的高精度动态控制,验证控制策略的稳定性与响应性能。文档详细介绍了仿真模型的搭建流程、关键参数的整定方法、系统动态波形的分析手段以及仿真结果的有效性验证,体现了经典自动控制理论在实际电机系统中的工程应用,是电机控制与电力电子技术相结合的典型研究案例。; 适合人群:具备自动控制原理、电机与拖动基础、电力电子技术和Matlab/Simulink仿真能力的电气工程、自动化、机电一体化等专业的本科生、研究生及从事电机驱动系统研发的工程技术人员。; 使用场景及目标:①作为高校课程设计或实验教学材料,帮助学生深入理解双闭环调速系统的工作机理与工程实现;②服务于科研项目,为新型电机控制算法(如滑模、模糊PID等)的开发与性能对比提供基础仿真验证平台;③作为工业界产品前期设计的仿真工具,用于评估不同控制策略在动态响应、抗干扰能力和稳态精度方面的可行性。; 阅读建议:建议读者在学习过程中紧密结合自动控制理论知识,亲手在Simulink环境中搭建完整的双闭环仿真模型,通过反复调整PI控制器的比例与积分参数,观察并分析转速、电流的阶跃响应曲线,从而深刻理解反馈控制的本质、系统稳定性条件以及参数整定对动态性能的影响,进而掌握电机控制系统的设计精髓。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值