我觉得有的人是根据括号的内容进来的,那么请你跳到第六点
一、程序介绍
可以非常方便地找到没有提交作业的同学。假如你们班有50人,交了46份作业,每份作业以名字命名,你可以使用这个程序快速找到哪4个同学没交。
二、使用方法
在任意一个文件夹的地址栏,输入smj,然后按回车键即可。
三、名单说明
首先检查当前文件夹有没有《名单.xlsx》,有则使用当前文件夹的名单。如果没有,将使用安装目录的《名单.xlsx》,你可以修改安装目录的《名单.xlsx》中的内容。
名单里每一行代表一个人。只要文件夹里出现这个人的任意一个信息就认为这个人已经交了作业。
四、程序安装说明
https://pan.baidu.com/s/1rUbLA8DVclpBrjlgbSCWHg?pwd=cn0x
把压缩包解压到任意目录,然后双击setup.exe即可。
五、原理
windows在找可执行程序的时候,首先在当前目录找,如果没有则到path指定的目录去找。我把smj的目录写 到path中。在任何位置,都可以找到smj.exe。然后.exe在输入命令的时候是可以省略的。另外,在地址栏输入smj其实就是在当前目录以及Path所指向的目录中找smj.exe并运行它。
六、开发过程
匹配文件和名单不是难事。我卡住的地方是如何让用户方便地使用。这个问题其实就是如何在电脑注册这个程序,使得这个程序可以随时随地被访问。我找了一些方法,可以通过sc命令,或者添加环境变量解决。但是对于电脑小白用户,让他们在自己的电脑注册一个程序的步骤还是过于复杂。所以我要写个setup.exe来帮用户做这些事。其实,我们使用软件之前,不都得经过安装吗?安装本质是什么?就是在电脑上配置好软件的环境,然后注册程序。但普通用户不需要知道这些,他们只需要双击setup.exe就可以让程序自动完成注册了。下面就是记录写这个setup.exe过程中进行的思考。
6.1 使用sc命令
sc create smj “binPath=F:\my university\learning\python\find_not_in\smj.exe” DisplayName= “smj”
会出现
[SC] OpenSCManager 失败 5:
网上找到的解决方案,是有效的
https://blog.csdn.net/m0_46212244/article/details/115833783
这个解决方案要去注册表修改某个值,然后重启。为了运行这个setup.exe,我必须让用户先去注册表改改东西,然后重启电脑。这违背了我最初的愿望“用户只需要双击setup.exe。
6.2 使用setx
setx用于修改环境变量。但是setx是覆盖不是追加。如果你的path原来有很多记录,直接使用setx会把原来的记录删去。解决方法是用 setx path “%path%;your_add_path”。%path%会返回原来的Path。但是又遇到问题,%path%返回的是system path 和user path的相加。部分用户的(比如我)system path 和 user path记录加起来超过了1024字符(一个环境变量最多支持1024个字符)导致写不全。超过1024字符的被截断了。于是找了很久很久,没有找到解决办法。另外配置system path是需要管理员权限的,这又让增加了用户需要知道的知识了,我得告诉用户要用管理员方式打开安装程序。这还是违背了原则,但这个在可接受范围内,毕竟右键->以管理员身份运行不是难事。
最后,我通过reg命令去找注册表关于user环境变量的记录。
reg query "HKEY_CURRENT_USER\Environment" -v path
这个命令可以查询user path。但它返回是这样的:
红框的三个不是我想要的,使用时需要裁去。
这样,我就拿到了原来的user path了。我需要做个字符串拼接,把原来的和待加的拼接在一起就行了。
然后我发现,配置user path是不用管理员权限的,很开心!
最终,setup.exe的代码如下,使用python编写, pyinstaller打包
import os
def get_windows_user_path()->str:
t=os.popen("reg query \"HKEY_CURRENT_USER\\Environment\" -v path")
t=t.read()
t=t.split() #以不可见字符为分隔符拆分字符串
t=t[3:] # 前3个元素不要
t=" ".join(t) # 如果path中有空格的话会被split掉,所有需要用join合并回来。以空格连接各个部分。
return t
def add_windows_user_path(path_need_add:str)->int:
org=get_windows_user_path()
org_list=org.split(";")
ex=False # 判断待添加的path是否已经存在了,如果存在就不需要添加了。
for aorg in org_list:
if(path_need_add==aorg):
ex=True
break
if ex:
return os.system("setx path \"{}\"".format(org))
if org[-1:]==";": #判断原来的path末尾是否有,如果没有则需要加上;再拼接待加的path
org+=path_need_add
else:
org+=";"+path_need_add
return os.system("setx path \"{}\"".format(org))
def set_windows_user_env(key:str,value:str)->int:
return os.system("setx \"{}\" \"{}\"".format(key,value))
if __name__=="__main__":
now_path=os.getcwd()
set_windows_user_env("smj",now_path)
add_windows_user_path("%smj%")
print("安装完成!")
os.system("pause")
smj的代码如下:
import os
import openpyxl
def ismatch(person,file_name):
for m in person:
if file_name.find(m)!=-1:
return True
return False
if __name__=="__main__":
now_path=os.getcwd()
root_path=os.environ.get('smj')
person_messages=[]
wb=None
try:
wb = openpyxl.load_workbook(os.path.join(now_path,"名单.xlsx"))
print("当前目录下有《名单.xlsx》,使用当前目录下的名单")
except:
try:
wb = openpyxl.load_workbook(os.path.join(root_path,"名单.xlsx"))
print("当前目录下没有《名单.xlsx》,使用安装目录({})下的《名单.xlsx》".format(root_path))
except:
print("在当前目录找不到名单.xlsx,安装目录:({})也没有《名单.xlsx》".format(root_path))
exit(0)
ws=wb.worksheets[0]
for row in ws.rows:
person=[]
for col in row:
value=col.value
if value:
person.append(str(value))
if len(person)>0:
person_messages.append(person)
wb.close()
person_submit_count=[[] for i in range(len(person_messages))]
folder=os.listdir(".")
for file in folder:
for i in range(len(person_messages)):
if(ismatch(person_messages[i],file)):
person_submit_count[i].append(file)
print("未交名单:")
for i in range(len(person_messages)):
if(len(person_submit_count[i])==0):
print("_".join(person_messages[i]))
print("重复提交名单:")
for i in range(len(person_messages)):
if(len(person_submit_count[i])>1):
print("_".join(person_messages[i])+" "+str(person_submit_count[i]))
os.system("pause")
七、其他思考
一开始我想到一个复杂但是可以满足更个性化需求的名单匹配方案。
名单的第一行为一个11~99的数字。
这些数字的含义我通过例子说明
11 表示属性1的第一种取值,12表示属性2的第二种取值。21表示属性2的第1种取值。
对于一个人,必须包含它的所有属性的某个取值才算提交。
比如有文件 张三_作业2。则程序返回张三_201907010101_作业1没交。
有文件201907010102_作业2则李四上交了作业2。
后来为什么没有采用这种方案呢?原因是这样的需求很个性,平时可能用到的不多。但是引入这种方案无疑增加了使用者的理解的负担。而且这种方案不是万能的,总会有更多的需求。如果为了一个不怎么使用到的需求牺牲大部分时间使用的方便性是得不偿失的。这也是我思考了很久放弃了这个较为复杂的使用方案,事实上,我可以增加高级匹配功能选项。对于普通使用,这个增加的功能没有任何影响。如果需要其他高级匹配,我可以去拓展,使用时增加相应的参数。这或许是很好的解决方案。我最终形成的思维是,可以为少数服务,但不可让多数收到少数的影响而变得麻烦。