Python操作JSON实现图书馆系统图书增删改功能咨询
图书馆系统CRUD功能修复与实现指南
1. 新增图书功能修复
你当前新增逻辑的核心问题是使用a追加模式直接往文件末尾写入单个JSON对象,完全没有读取原有数组结构,自然会把新数据写到闭合方括号外侧,破坏JSON格式。
正确实现逻辑:
- 先读取整个
books.json文件,解析为Python列表对象 - 将新构造的图书对象追加到列表末尾
- 以覆盖写入模式打开文件,将更新后的完整列表重新序列化为格式化JSON写回
修正后可直接运行的代码:
import json import os def addBook(self): print("Please fill in the following information:") author = input("Author: ") country = input("Country: ") image = input("Image Link: ") lang = input("Language: ") link = input("Link: ") # 增加输入校验,避免非数字输入导致程序崩溃 while True: try: pages = int(input("Pages: ")) break except ValueError: print("Invalid input, please enter a valid integer for pages!") title = input("Title: ") isbn = input("ISBN: ") while True: try: year = int(input("Year: ")) break except ValueError: print("Invalid input, please enter a valid integer for year!") new_book = { "author": author, "country": country, "imageLink": image, "language": lang, "link": link, "pages": pages, "title": title, "ISBN": isbn, "year": year } # 读取原有图书数据 with open("books.json", "r", encoding="utf-8") as f: book_list = json.load(f) # 追加新图书到列表 book_list.append(new_book) # 全量写回文件 with open("books.json", "w", encoding="utf-8") as f: json.dump(book_list, f, indent=2, ensure_ascii=False) print("Book added successfully!")
补充说明:写文件时指定indent=2可以保持JSON格式化易读,ensure_ascii=False避免非英文内容被转义为乱码。
2. 图书选择功能修复
你现有选择逻辑的两个明显问题:
- 只打印了匹配序号,但没有存储序号和原数据的对应关系,用户输入序号后无法定位到具体图书
- 同一本书如果同时匹配作者、书名关键词,会被重复打印两次
修正思路:新增匹配结果列表,存储命中图书在原数据中的索引,用户输入合法序号后直接返回对应索引,供编辑、删除功能调用。
修正后代码:
def selectCatalogue(self): os.system('cls') keyword = input("Please fill the author or title of the book in: ").casefold() match_results = [] # 存储匹配图书在原列表中的索引 # 读取最新的图书数据,不依赖全局变量 with open("books.json", "r", encoding="utf-8") as f: data = json.load(f) print("=== Search Results ===") for idx, book in enumerate(data): # 作者或书名任意一个命中就算匹配,避免重复打印 if keyword in book['author'].casefold() or keyword in book['title'].casefold(): current_num = len(match_results) + 1 print(f'[{current_num}] Author: {book["author"]}') print(f' Country: {book["country"]}') print(f' Image link: {book["imageLink"]}') print(f' Language: {book["language"]}') print(f' Link: {book["link"]}') print(f' Pages: {book["pages"]}') print(f' Title: {book["title"]}') print(f' ISBN: {book["ISBN"]}') print(f' Year: {book["year"]}') print(' ') match_results.append(idx) if not match_results: print("No matching books found!") return None # 校验用户输入合法性 while True: try: choice = int(input("Please enter the number of the book you want to select: ")) if 1 <= choice <= len(match_results): # 返回选中图书在原数据列表中的索引 return match_results[choice-1] else: print(f"Please enter a number between 1 and {len(match_results)}") except ValueError: print("Invalid input, please enter a valid number!")
3. 图书编辑功能修复
你现有编辑逻辑的错误点:
- 没有获取选中图书的索引,直接对整个列表做字段赋值,逻辑完全不成立
- 存在字段赋值笔误:修改页数时错误赋值给了author字段
- ISBN是字符串类型,转成整数会丢失前导零、超出数值范围引发报错
- 修改后没有将更新后的数据写回文件
修正后代码:
def editBook(self): # 先获取选中图书的索引 target_idx = self.selectCatalogue() if target_idx is None: print("No book selected, return to main menu") return print("=== Select Field to Edit ===") print('[1] Author') print('[2] Country') print('[3] Image link') print('[4] Language') print('[5] Link') print('[6] Pages') print('[7] Title') print('[8] ISBN') print('[9] Year') # 读取全量图书数据 with open("books.json", "r", encoding="utf-8") as f: book_list = json.load(f) target_book = book_list[target_idx] # 选择要修改的字段 while True: choice = input("Enter the field number: ") if choice == '1': target_book["author"] = input("Please enter the new author name: ") break elif choice == '2': target_book["country"] = input("Please enter the new country name: ") break elif choice == '3': target_book["imageLink"] = input("Please enter the new image link: ") break elif choice == '4': target_book["language"] = input("Please enter the new language: ") break elif choice == '5': target_book["link"] = input("Please enter the new link: ") break elif choice == '6': while True: try: target_book["pages"] = int(input("Please enter the new number of pages: ")) break except ValueError: print("Invalid input, please enter a valid number!") break elif choice == '7': target_book["title"] = input("Please enter the new title: ") break elif choice == '8': # ISBN保持字符串类型,不做整数转换 target_book["ISBN"] = input("Please enter the new ISBN: ") break elif choice == '9': while True: try: target_book["year"] = int(input("Please enter the new year: ")) break except ValueError: print("Invalid input, please enter a valid number!") break else: print("Invalid choice, please enter a number between 1 and 9") # 将更新后的数据全量写回文件 with open("books.json", "w", encoding="utf-8") as f: json.dump(book_list, f, indent=2, ensure_ascii=False) print("Book information updated successfully!")
4. 图书删除功能实现
删除逻辑和编辑逻辑高度一致:先选中目标图书,从列表中移除对应元素后全量写回文件即可,参考代码:
def deleteBook(self): target_idx = self.selectCatalogue() if target_idx is None: print("No book selected, return to main menu") return # 读取全量数据 with open("books.json", "r", encoding="utf-8") as f: book_list = json.load(f) # 移除选中的图书 deleted_book = book_list.pop(target_idx) # 写回更新后的数据 with open("books.json", "w", encoding="utf-8") as f: json.dump(book_list, f, indent=2, ensure_ascii=False) print(f"Book '{deleted_book['title']}' has been deleted successfully!")
通用优化建议
- 所有JSON文件读写操作统一指定
encoding="utf-8",避免Windows系统默认GBK编码导致的乱码问题 - 可以把JSON文件的读取、写入逻辑抽成公共工具函数,减少重复代码
- 涉及文件写入操作时,建议先写临时文件再替换原文件,避免程序中途崩溃损坏原有数据
- 对ISBN这类固定格式字段,可以增加格式校验,提升数据合法性
内容的提问来源于stack exchange,提问作者jb18
相关产品推荐
相关产品推荐

