Go语言实战案例 — 项目实战篇:图书管理系统(文件存储)

在学习 Go 的过程中,很多同学会做一些小型实战项目来加深理解。本篇带来的案例是一个图书管理系统 ,它采用 文件存储 的方式保存数据(JSON 文件),避免了引入数据库的复杂度,非常适合作为入门级的项目实践。


一、项目目标

我们要实现一个简易的命令行版 图书管理系统,功能如下:

  • ✅ 添加图书(标题、作者、价格)
  • ✅ 删除图书(根据 ID)
  • ✅ 查询图书(按 ID 或标题模糊搜索)
  • ✅ 列出所有图书
  • ✅ 数据持久化(保存到 JSON 文件,程序退出后数据不丢失)

二、系统设计

数据结构:

go 复制代码
type Book struct {
    ID     int     `json:"id"`
    Title  string  `json:"title"`
    Author string  `json:"author"`
    Price  float64 `json:"price"`
}
  • 每本书有唯一 ID
  • 图书列表存放在一个 []Book
  • 数据通过 JSON 序列化存储到 books.json

模块划分:

  1. 数据持久化层:负责加载和保存 JSON 文件
  2. 业务逻辑层:增删改查操作
  3. 命令行交互层:菜单驱动

三、完整代码示例

go 复制代码
package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"os"
	"strings"
)

// Book 图书结构体
type Book struct {
	ID     int     `json:"id"`
	Title  string  `json:"title"`
	Author string  `json:"author"`
	Price  float64 `json:"price"`
}

// 全局图书切片
var books []Book
var dataFile = "books.json"

// 加载图书数据
func loadBooks() {
	file, err := ioutil.ReadFile(dataFile)
	if err != nil {
		if os.IsNotExist(err) {
			books = []Book{}
			return
		}
		fmt.Println("加载数据失败:", err)
		return
	}
	_ = json.Unmarshal(file, &books)
}

// 保存图书数据
func saveBooks() {
	data, err := json.MarshalIndent(books, "", "  ")
	if err != nil {
		fmt.Println("保存数据失败:", err)
		return
	}
	_ = ioutil.WriteFile(dataFile, data, 0644)
}

// 添加图书
func addBook(title, author string, price float64) {
	id := 1
	if len(books) > 0 {
		id = books[len(books)-1].ID + 1
	}
	book := Book{ID: id, Title: title, Author: author, Price: price}
	books = append(books, book)
	saveBooks()
	fmt.Println("✅ 图书添加成功:", book)
}

// 删除图书
func deleteBook(id int) {
	index := -1
	for i, b := range books {
		if b.ID == id {
			index = i
			break
		}
	}
	if index == -1 {
		fmt.Println("❌ 未找到该 ID 的图书")
		return
	}
	books = append(books[:index], books[index+1:]...)
	saveBooks()
	fmt.Println("✅ 图书删除成功")
}

// 查询图书
func searchBook(keyword string) {
	keyword = strings.ToLower(keyword)
	found := false
	for _, b := range books {
		if strings.Contains(strings.ToLower(b.Title), keyword) || fmt.Sprintf("%d", b.ID) == keyword {
			fmt.Printf("📖 ID:%d | 标题:%s | 作者:%s | 价格:%.2f\n", b.ID, b.Title, b.Author, b.Price)
			found = true
		}
	}
	if !found {
		fmt.Println("🔍 未找到匹配的图书")
	}
}

// 列出所有图书
func listBooks() {
	if len(books) == 0 {
		fmt.Println("暂无图书")
		return
	}
	fmt.Println("📚 图书列表:")
	for _, b := range books {
		fmt.Printf("ID:%d | 标题:%s | 作者:%s | 价格:%.2f\n", b.ID, b.Title, b.Author, b.Price)
	}
}

// 主菜单
func main() {
	loadBooks()
	for {
		fmt.Println("\n==== 图书管理系统 ====")
		fmt.Println("1. 添加图书")
		fmt.Println("2. 删除图书")
		fmt.Println("3. 查询图书")
		fmt.Println("4. 列出所有图书")
		fmt.Println("5. 退出")
		fmt.Print("请输入选项: ")

		var choice int
		fmt.Scanln(&choice)

		switch choice {
		case 1:
			var title, author string
			var price float64
			fmt.Print("输入标题: ")
			fmt.Scanln(&title)
			fmt.Print("输入作者: ")
			fmt.Scanln(&author)
			fmt.Print("输入价格: ")
			fmt.Scanln(&price)
			addBook(title, author, price)
		case 2:
			var id int
			fmt.Print("输入要删除的图书ID: ")
			fmt.Scanln(&id)
			deleteBook(id)
		case 3:
			var keyword string
			fmt.Print("输入图书ID或标题关键字: ")
			fmt.Scanln(&keyword)
			searchBook(keyword)
		case 4:
			listBooks()
		case 5:
			fmt.Println("退出系统,再见!👋")
			return
		default:
			fmt.Println("无效选项,请重新输入")
		}
	}
}

四、运行效果

bash 复制代码
$ go run main.go
==== 图书管理系统 ====
1. 添加图书
2. 删除图书
3. 查询图书
4. 列出所有图书
5. 退出
请输入选项: 1
输入标题: Go语言实战
输入作者: 张三
输入价格: 59.9
✅ 图书添加成功: {1 Go语言实战 张三 59.9}

再次运行,可以看到数据被保存到 books.json,实现了持久化。


五、总结与扩展

这个简易的图书管理系统涵盖了文件读写、JSON 序列化、数据结构操作、命令行交互等知识点,是 Go 入门的非常好的练手项目。

相关推荐
何中应4 分钟前
如何截取PDF内容为图片
java·开发语言·后端·pdf
Jenwein25 分钟前
Linux中使用docker的网络问题
后端·docker
华仔啊37 分钟前
这20条SQL优化方案,让你的数据库查询速度提升10倍
数据库·后端·mysql
非凡ghost1 小时前
Syncovery Premium(文件同步软件)
前端·javascript·后端
小彤花园1 小时前
GooglePlay更改签名秘钥报错(2025最新版)
android·google
猪猪拆迁队1 小时前
前端图形架构设计:AI生成设计稿落地实践
前端·后端·ai编程
非凡ghost1 小时前
BiliLive-tools(B站录播一站式工具) 中文绿色版
前端·javascript·后端
非凡ghost1 小时前
bkViewer小巧精悍数码照片浏览器 中文绿色版
前端·javascript·后端
间彧1 小时前
Java并发编程:乐观锁、悲观锁、公平锁、非公平锁
后端
间彧1 小时前
Java并发编程锁机制解析:乐观锁、悲观锁、公平锁、非公平锁、可重入锁、独占锁、共享锁
后端