本文是关于学生信息管理系统的“进阶”,完善了各种逻辑,也增加了一些自定义的方法,同时引入了文件句柄操作txt文件(读取和写入),让程序运行更加贴近“现实”。(完整代码在文末附上)
关于“学生信息管理系统”的基本思路和详细过程,本文不再赘述,请查看上一篇文章。
V2.0版本相较于V1.0,功能逻辑更为完善,但其主要区别在于增加了读取和写入文件的操作。
①首先讲关于读取文件的操作,即为简单的按行读取依次遍历。
读取文件采用open(),其中路径非绝对路径(可自行修改)
1. # 定义一个方法用于读取文件: 2. def readTxt() -> list: 3. emptyList1 = [] 4. emptyList2 = [] 5. 6. f = open("./test.txt", 'r', encoding='UTF-8') 7. 8. # 把txt文件中的每一行学生信息,存储为新列表emptyList2的元素, 9. for i in f: 10. a = str(i) 11. b = a.replace('\n', '') 12. emptyList2.append(b.split("\t")) 13. 14. # 依次将emptyList2的三种学生信息,存入字典, 15. while len(emptyList1) < len(emptyList2): 16. for j in range(0, len(emptyList2)): 17. name = emptyList2[j][0] 18. sex = emptyList2[j][1] 19. phone = emptyList2[j][2] 20. 21. Dict = {"name": name, "sex": sex, "phone": phone} 22. # 把该字典作为新列表emptyList1的一个元素存入。 23. emptyList1.append(Dict) 24. 25. f.close() 26. 27. # 最后结束方法,返回列表emptyList1,该列表是txt文件里边全部的信息。信息存储在列表里边的字典 28. return emptyList1
②写入文件
分为a模式和w模式
a模式为追加写入
w模式:只写入模式,文件不存在则建立,将文件里边的内容先删除再写入
③该程序是实时更新txt文件中的内容的,如果想简化为只在退出瞬间完成写入,即在主菜单的第五个功能调用写入文件的方法以及对其他代码稍加修改即可
下面附上完整代码:
1. # -*- coding: utf-8 -*- 2. # @Author:︶ㄣ释然 3. # @Time: 2022/7/6 22:08 4. 5. # 定义方法查找同名 6. def checkTheSameName(studentMessageList, enterName) -> (list, str): 7. flagList = [] # 存的是名字的索引 8. List = [] 9. returnList = [] 10. # 开始遍历查找 11. for i in range(0, len(studentMessageList)): 12. if studentMessageList[i]["name"] == enterName: 13. # 把找到的名字对应的索引,添加进列表 14. flagList.append(int(i)) 15. 16. if len(flagList) == 1: 17. # 说明信息中只存在一个这样的名字 18. return len(flagList) # 返回1表示不重名 19. 20. if len(flagList) > 1: 21. for i in flagList: 22. List.append(studentMessageList[i]) 23. # 此时,List的长度等于flagList 24. 25. returnList.append(List) 26. returnList.append(flagList) 27. return returnList # 第一个元素是列表,第二个元素是存储重复名字的索引的 列表 28. 29. 30. # 定义一个方法用于使用a模式写入文件:传入已经存好学生信息的列表,然后遍历写入txt文档 31. def writeTxt_aMode(studentList): 32. # 自带文件关闭功能,不需要再写f.close() 33. 34. # 这里的test.txt没有写路径,默认在同一文件夹下 35. # a:追加写入 ,文件不存在则建立,在文件最后写入,也就是说指针在文件最后 36. with open("test.txt", "a", encoding="utf-8") as f: 37. for i in range(0, len(studentList)): 38. DICT = studentList[i] 39. if i == len(studentList) - 1: 40. f.write("{0}\t{1}\t{2}".format(DICT["name"], DICT["sex"], DICT["phone"])) 41. else: 42. f.write("{0}\t{1}\t{2}\n".format(DICT["name"], DICT["sex"], DICT["phone"])) 43. 44. 45. # 定义一个方法用于使用w模式写入文件:传入已经存好变更好信息的列表,然后遍历写入txt文档 46. def writeTxt_wMode(studentList): 47. # w:只写入模式,文件不存在则建立,将文件里边的内容先删除再写入 48. with open("test.txt", "w", encoding="utf-8") as f: 49. for i in range(0, len(studentList)): 50. DICT = studentList[i] 51. 52. if i == len(studentList) - 1: 53. f.write("{0}\t{1}\t{2}".format(DICT["name"], DICT["sex"], DICT["phone"])) 54. else: 55. f.write("{0}\t{1}\t{2}\n".format(DICT["name"], DICT["sex"], DICT["phone"])) 56. 57. 58. # 该方法主要解决:当txt文档有信息的前提下,继续添加信息无法换行问题。 59. # 即在后边插入"\n" 60. def writeTxt_lineFeed(string): 61. with open("test.txt", "a", encoding="utf-8") as f: 62. f.write(string) 63. 64. 65. # 定义一个方法用于读取文件: 66. def readTxt() -> list: 67. emptyList1 = [] 68. emptyList2 = [] 69. 70. f = open("./test.txt", 'r', encoding='UTF-8') 71. 72. # 把txt文件中的每一行学生信息,存储为新列表emptyList2的元素, 73. for i in f: 74. a = str(i) 75. b = a.replace('\n', '') 76. emptyList2.append(b.split("\t")) 77. 78. # 依次将emptyList2的三种学生信息,存入字典, 79. while len(emptyList1) < len(emptyList2): 80. for j in range(0, len(emptyList2)): 81. name = emptyList2[j][0] 82. sex = emptyList2[j][1] 83. phone = emptyList2[j][2] 84. 85. Dict = {"name": name, "sex": sex, "phone": phone} 86. # 把该字典作为新列表emptyList1的一个元素存入。 87. emptyList1.append(Dict) 88. 89. f.close() 90. 91. # 最后结束方法,返回列表emptyList1,该列表是txt文件里边全部的信息。信息存储在列表里边的字典 92. return emptyList1 93. 94. 95. # 定义一个方法,去除字符串左右两端的空格,并返回处理之后的字符串 96. def trim(strings): 97. # 获取从偏移为0的字符一直到偏移为1的字符串,不包括偏移为1的字符串 98. # (该功能用于去除字符串左边的空格) 99. while strings[:1] == ' ': 100. strings = strings[1:] 101. # 获取从偏移为-1的字符一直到偏移为最后一位的字符串,不包括偏移为最后一位的字符串 102. # (该功能用于去除字符串右边的空格) 103. while strings[-1:] == ' ': 104. strings = strings[:-1] 105. # 左右两端空格去除完成,返回strings 106. return strings 107. 108. 109. # 定义一个方法,检查输入的电话号码是否符合规范 110. def checkPhoneNumber_Boolean(phone): 111. if phone.isdigit(): 112. return True 113. else: 114. print("输入无效,重新录入信息") 115. return False 116. 117. 118. # 1、添加学生信息 119. def addStudentsMessage(): 120. List = [] 121. date = 0 122. while True: 123. infer = input("你是否想输入学生信息:y/n:") 124. 125. if infer == "y" or infer == "Y": 126. 127. name = input("请输入学生的姓名:") 128. if not name: 129. print("学生姓名不能为空") 130. return 131. 132. # 调用方法去除字符串的空格再进行比较,如果去除空格之后为空,则说明键入的字符串只有空格 133. if trim(name) == "": 134. print("学生姓名不能为空") 135. return 136. 137. # 如果上述逻辑都通过,说明名字输入合法,此处调用方法去除name左右两端的空格,以达到更加规范的效果 138. name = trim(name) 139. 140. # 判断性别输入是否正确 141. while True: 142. sex = input("请输入学生的性别(F/M):") 143. if sex == "F" or sex == "M": 144. break 145. else: 146. continue 147. 148. # 判断电话输入是否正确 149. while True: 150. phone = input("请输入学生的电话号码:") 151. # 调用自定义的检查方法,返回布尔类型 152. resultBoolean = checkPhoneNumber_Boolean(phone) 153. if resultBoolean: 154. break 155. else: 156. continue 157. 158. Dict = {"name": name, "sex": sex, "phone": phone} 159. 160. List.append(Dict) 161. print("学生已添加") 162. 163. date += 1 164. elif infer == "n" or infer == "N": 165. break 166. else: 167. print("输入格式有误") 168. 169. if date == 0: 170. print("未存入数据") 171. else: 172. return List 173. 174. 175. # 2、删除学生信息 176. def deleteMessage(studentMessageList) -> list: 177. # 定义信号位 178. flag = True 179. 180. enterName = str(input("请输入要删除的姓名:")) 181. 182. for i in range(0, len(studentMessageList)): 183. if studentMessageList[i]["name"] == enterName: 184. flag = False 185. break 186. 187. if flag: 188. print("学生不存在") 189. # 学生不存在则没有必要查找是否同名 190. return studentMessageList 191. 192. # 开始遍历查找 193. accept = checkTheSameName(studentMessageList, enterName) # 接收查找同名方法的返回值 194. 195. try: 196. if int(accept) == 1: 197. for i in range(0, len(studentMessageList)): 198. if studentMessageList[i]["name"] == enterName: 199. del studentMessageList[i] 200. print("删除成功") 201. # 删除成功直接返回,结束该方法 202. return studentMessageList 203. except: 204. # 此时出现同名,accept[0]和accept[1]都是列表对象 205. # accept[0]存储的是同名学生信息 206. show(accept[0]) 207. # 告诉用户有同名 208. deleteNumber = int(input("出现同名,请选择要删除哪一个学生的序号")) - 1 209. 210. for j in range(0, int(len(accept[0]))): 211. if j == deleteNumber: 212. # accept[1]存储的是同名学生,出现在原来的最初传进来的学生列表当中的索引 213. del studentMessageList[accept[1][j]] 214. print("删除成功") 215. return studentMessageList 216. 217. 218. # 3、修改学生信息 219. def change(List): 220. if List is None: 221. print("没有信息,无法修改") 222. return None 223. if len(List) == 0: 224. print("没有信息,无法修改") 225. return None 226. if len(List) != 0: 227. flag = True 228. inputName = str(input("请输入要修改的学生姓名:")) 229. 230. for i in range(0, len(List)): 231. if List[i]["name"] == inputName: 232. flag = False 233. break 234. 235. if flag: 236. print("学生不存在") 237. return List 238. 239. accept = checkTheSameName(List, inputName) # 接收查找同名方法的返回值 240. 241. try: 242. if int(accept) == 1: 243. for i in range(0, len(List)): 244. if List[i]["name"] == inputName: 245. # 进入这个if,说明找到了该学生 246. # 1、修改性别 247. while True: 248. sexMessage = input("输入修改后的学生性别(F/M):") 249. if sexMessage == "F" or sexMessage == "M": 250. List[i]["sex"] = sexMessage 251. break 252. else: 253. continue 254. # 2、修改电话 255. while True: 256. phone = input("请输入修改后的学生电话号码:") 257. # 调用自定义的检查方法,返回布尔类型 258. resultBoolean = checkPhoneNumber_Boolean(phone) 259. if resultBoolean: 260. List[i]["phone"] = phone 261. break 262. else: 263. continue 264. print("修改成功") 265. # 上面全部修改完成且没有错误,则结束方法,并且返回列表 266. return List 267. except: 268. # 此时出现同名,accept[0]和accept[1]都是列表对象 269. 270. # accept[0]存储的是同名学生信息 271. show(accept[0]) 272. # 告诉用户有同名 273. deleteNumber = int(input("出现同名,请选择要修改哪一个学生的序号")) - 1 274. 275. for j in range(0, int(len(accept[0]))): 276. if j == deleteNumber: 277. # accept[1]存储的是同名学生,出现在原来的最初传进来的学生列表当中的索引 278. 279. # #这个List[accept[1][j]] 即是用户要修改的这个学生的信息 280. while True: 281. sexMessage = input("输入修改后的学生性别(F/M):") 282. if sexMessage == "F" or sexMessage == "M": 283. List[accept[1][j]]["sex"] = sexMessage 284. break 285. else: 286. continue 287. 288. # 2、修改电话 289. while True: 290. phone = input("请输入修改后的学生电话号码:") 291. # 调用自定义的检查方法,返回布尔类型 292. resultBoolean = checkPhoneNumber_Boolean(phone) 293. if resultBoolean: 294. List[accept[1][j]]["phone"] = phone 295. break 296. else: 297. continue 298. print("修改成功") 299. 300. # 上面全部修改完成且没有错误,则结束方法,并且返回列表 301. return List 302. 303. # 循环走完没有结束方法,说明不存在 304. print("学生不存在") 305. 306. 307. # 4、显示所有学生信息 308. def show(List): 309. print("学生信息如下:") 310. print("=" * 30) 311. 312. # 打印头部标题 并进行格式化 313. print("{0:^10}\t{1:^12}\t{2:^10}\t{3:^15}".format("学生序号", "学生姓名", "学生性别", "电话号码")) 314. 315. if List is None: 316. return None 317. if len(List) == 0: 318. return None 319. if len(List) != 0: 320. for i in range(0, len(List)): 321. # 格式化字符串 322. # 最后的那个chr(12288)是用于解决中文对不齐的问题 323. print("{0:^13}\t{1:^13}\t{2:^13}\t{3:>15}". 324. format(i + 1, List[i].get("name"), List[i].get("sex"), List[i].get("phone")), chr(12288)) 325. 326. 327. # 主菜单 328. def mainMenu(): 329. LIST1 = [] 330. 331. # 把文件里边的学生信息添加到LIST1里边,如果发现文件里边的学生信息为空,则继续执行后面的程序 332. try: 333. for i in readTxt(): 334. LIST1.append(i) 335. except: 336. pass 337. 338. while True: 339. print("=" * 30) 340. print("学生信息管理系统V2.0\n1、添加学生信息\n2、删除学生信息\n" 341. "3、修改学生信息\n4、显示所有学生信息\n5、退出系统") 342. print("=" * 30) 343. 344. date = input("请输入功能对应的数字:") 345. 346. if date == "1": 347. # 1、添加学生信息(调用自定义函数) 348. LIST = addStudentsMessage() # 由于返回的是列表,所以这里用一个新的列表接收 349. if LIST is None: 350. continue 351. for i in range(0, len(LIST)): 352. LIST1.append(LIST[i]) 353. 354. try: 355. if len(readTxt()) == 0: 356. writeTxt_aMode(LIST) 357. else: 358. # 换行 359. writeTxt_lineFeed("\n") 360. 361. writeTxt_aMode(LIST) 362. except: 363. pass 364. 365. if date == "2": 366. # 2、删除学生信息(调用自定义函数) 367. # try过滤掉学生姓名查找不存在的情况 368. try: 369. deleteList = deleteMessage(LIST1) 370. writeTxt_wMode(deleteList) 371. except: 372. pass 373. 374. if date == "3": 375. # 3、修改学生信息(调用自定义函数) 376. # try过滤掉学生姓名查找不存在的情况 377. try: 378. changeList = change(LIST1) 379. writeTxt_wMode(changeList) 380. except: 381. pass 382. 383. if date == "4": 384. # 4、显示所有学生信息(调用自定义函数) 385. show(LIST1) 386. if date == "5": 387. # 退出系统 388. ask = input("真的要退出吗?(yes or no):") 389. if ask == "yes" or ask == "Yes" or ask == "YES": 390. print("\n已退出") 391. break 392. if ask == "no" or ask == "No" or ask == "NO": 393. continue 394. print("输入有误") 395. 396. 397. # 调用主菜单函数 398. if __name__ == '__main__': 399. mainMenu()