Go练习题(9)
程序员文章站
2022-07-01 19:11:15
...
在之前的用户管理的基础上使用Json做持久化
目录节构都一致
方法一:
//main.go
package main
import (
"fmt"
"github.com/strive-after/users/lib"
)
func main() {
var (
user string
menu string
)
if !lib.Auth() {
fmt.Println("您输入的密码错误,系统退出")
return
}
for {
//界面打印
menu = `====================
欢迎使用用户管理系统
====================
1.添加用户
2.查找用户
3.修改用户
4.删除用户
5.修改密码
6.退出程序
====================`
fmt.Println(menu)
//用户选择
user = lib.Inputstring("请输入指令:")
fmt.Println("====================")
if user == "1" {
lib.Add(lib.GetId())
} else if user == "2" {
lib.Sel()
} else if user == "3" {
lib.Change()
} else if user == "4" {
lib.Del()
} else if user == "5" {
lib.SetPassword()
}else if user == "6"{
break
} else {
fmt.Println("输入有误请重新输入")
continue
}
}
}
//load&save.go
package lib
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"time"
)
const userpath string = "./user.json"
//存储用户信息
func SaveUser(UserInfo map[int]User) {
//对文件重命名 加时间后缀
if _,err := os.Stat(userpath); err == nil{
// //os.Rename(userpath,fmt.Sprintf("%x",time.Now())+".user.csv")
os.Rename(userpath,strconv.FormatInt(time.Now().Unix(),10)+".user.json")
}
//删除文件 保留3个最新的
if filebak,err := filepath.Glob("*.user.json");err == nil{
// //默认是升序 我们要保留最新的 就用倒叙的方式排序 删除3个以后的ok
sort.Sort(sort.Reverse(sort.StringSlice(filebak)))
//fmt.Println(filebak)
if len(filebak) >= 3 {
for _,v := range filebak[3:]{
os.Remove(v)
}
}
}
if file,err := os.Create(userpath);err == nil {
defer file.Close()
encode := json.NewEncoder(file)
//格式化
encode.SetIndent("","\t")
encode.Encode(UserInfo)
}
}
//加载用户信息
func LoadUser() map[int]User {
UserInfo := map[int]User{}
//判断文件是否存在
if file,err := os.Open(userpath);err == nil {
defer file.Close()
//创建解码器
decode := json.NewDecoder(file)
//将流中的数据编码到对象中 这里UserInfo 是对象 要取指针
decode.Decode(&UserInfo)
}else { //这里err != nil
if !os.IsNotExist(err) { //如果不是因为文件不存在 打印报错
fmt.Printf("[-]发生错误%v",err)
}
}
return UserInfo
}
//import.go
package lib
import (
"bufio"
"fmt"
"os"
"strings"
"time"
)
//因为需要用户输入的比较多定义一个input函数
func Inputstring(input string) string {
//这里使用带缓冲的io
//创建scanner
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf(input)
//获取用户信息
scanner.Scan()
//返回读取的行信息 text每次读一行
return strings.TrimSpace(scanner.Text())
}
func Inputuser(id int) {
UserInfo := LoadUser()
var user User
var err error
START:
user.ID = id
user.Name = Inputstring("请输入名字:")
user.Birthday,err = time.Parse("2006-1-2",Inputstring("请输入生日(如2006-1-2):"))
user.Tel = Inputstring("请输入联系方式:")
user.Addr = Inputstring("请输入住址:")
user.Desc = Inputstring("请输入备注:")
if err == nil {
for k,v := range UserInfo {
if k == id {
break
}else if v.Name == user.Name {
fmt.Println("用户已存在,请重新输入")
fmt.Println(strings.Repeat("-", 20))
goto START
}else if user.Name == ""{
fmt.Println("用户名不能为空,请重新输入")
goto START
}
}
UserInfo[id] = user
SaveUser(UserInfo)
}else {
fmt.Println("格式有误,请重新输入")
goto START
}
}
//auth.go
package lib
import (
"crypto/md5"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/howeyc/gopass"
)
//定义密码输入次数
//定义用户结构体
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Birthday time.Time `json:"birthday"`
Tel string `json:"tel"`
Addr string `json:"addr"`
Desc string `json:"desc"`
}
const (
passwordFile = "./passworld"
maxauth = 3
)
func GetId() int {
var id int
UserInfo := LoadUser()
for k,_ := range UserInfo {
if id < k {
id = k
}
}
return id + 1
}
//使用系统前输入密码 超过3次则退出系统
func Auth() bool {
//password, err := os.Open(passwordFile)
password ,err := ioutil.ReadFile(passwordFile)
//打开密码文件如果err!=nil 就是说打开有问题
if err != nil || len(password) < 1 {
//如果是因为不存在 那么我们需要初始化密码
if os.IsNotExist(err) || len(password) < 1 {
fmt.Print("请输入初始化密码:")
bytes, _ := gopass.GetPasswd()
//将用户输入的密码md5加密 写入文件
ioutil.WriteFile(passwordFile, []byte(fmt.Sprintf("%x",md5.Sum(bytes))), 0644)
return true
} else { //如果不是因为不存在 那么打印报错信息
fmt.Println(err)
}
} else { //如果存在 那么就需要做密码验证
//defer password.Close()
for i := 1; i <= maxauth; i++ {
// user := Inputstring("请输入密码:")
fmt.Printf("请输入密码:")
bytes, _ := gopass.GetPasswd()
//这里对输入的密码进行md5加密并且与常量比较
//%x是小写十六进制表示 Sprintf格式化返回一个字符串
passwd ,_:= ioutil.ReadFile(passwordFile)
if fmt.Sprintf("%x", md5.Sum(bytes)) == string(passwd) {
return true
} else {
fmt.Printf("输入错误请重新输入,您还有%d次机会\n", maxauth-i)
}
}
return false
}
return false
}
func SetPassword() {
fmt.Printf("请输入旧密码:")
bytes, _ := gopass.GetPasswd()
if passwd ,_:= ioutil.ReadFile(passwordFile);string(passwd) == fmt.Sprintf("%x",md5.Sum(bytes)){
fmt.Print("请输入新密码")
bytes, _ := gopass.GetPasswd()
ioutil.WriteFile(passwordFile, []byte(fmt.Sprintf("%x",md5.Sum(bytes))), 0644)
fmt.Println("密码修改成功")
}else {
fmt.Println("密码输入错误")
}
}
//add.go
package lib
import "fmt"
//添加用户
func Add(id int) {
Inputuser(id)
fmt.Println("[+]添加成功")
}
//修改用户
//change.go
package lib
import (
"fmt"
"strconv"
"strings"
)
func Change() {
UserInfo := LoadUser()
if id, err := strconv.Atoi(Inputstring("请输入修改的用户id:")); err == nil {
fmt.Println(strings.Repeat("-", 20))
if user, ok := UserInfo[id]; ok {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n",user.ID, user.Name,user.Birthday.Format("2006-1-2"),user.Tel,user.Addr,user.Desc)
fmt.Println(strings.Repeat("-", 20))
affirm := Inputstring("确认是否修改(Y/N):")
if affirm == "Y" || affirm == "y" {
Inputuser(id)
}
} else {
fmt.Println("用户id不存在")
}
} else {
fmt.Println("输入错误")
}
}
//查询用户
//sel.go
package lib
import (
"fmt"
"sort"
"strings"
)
func Sel() {
UserInfo := LoadUser()
user := Inputstring("请输入要查询的信息:")
list := make([]User,0)
fmt.Println(strings.Repeat("-", 20))
for _, v := range UserInfo {
if strings.Contains(v.Name, user) || strings.Contains(v.Desc, user) || strings.Contains(v.Addr, user) || strings.Contains(v.Tel, user) || strings.Contains(v.Birthday.Format("2006-01-02"), user) {
list = append(list,v)
}
}
users := Inputstring("请输入要排序的属性(ID,Name,Desc,Addr,Tel,Birthday):")
sort.Slice(list, func(i, j int) bool {
switch users {
case "ID":
return list[i].ID < list[j].ID
case "Name":
return list[i].Name < list[j].Name
case "Desc":
return list[i].Desc < list[j].Desc
case "Addr":
return list[i].Addr < list[j].Addr
case "Tel":
return list[i].Tel < list[j].Tel
case "Birthday":
return list[i].Birthday.Format("2006-1-2") < list[j].Birthday.Format("2006-1-2")
default:
return list[i].ID < list[j].ID
}
})
for _,v := range list {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n", v.ID,v.Name,v.Birthday.Format("2006-1-2"),v.Tel,v.Addr,v.Desc)
fmt.Println(strings.Repeat("-", 20))
}
}
//del.go
//删除用户
package lib
import (
"fmt"
"strconv"
"strings"
)
func Del() {
UserInfo := LoadUser()
if id, err := strconv.Atoi(Inputstring("请输入删除的用户id:")); err == nil {
fmt.Println(strings.Repeat("-", 20))
if user, ok := UserInfo[id]; ok {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n",user.ID ,user.Name,user.Birthday.Format("2006-1-2"),user.Tel,user.Addr,user.Desc)
fmt.Println(strings.Repeat("-", 20))
affirm := Inputstring("确认是否删除(Y/N):")
if affirm == "Y" || affirm == "y" {
delete(UserInfo, id)
SaveUser(UserInfo)
fmt.Println("[-]删除成功")
}
} else {
fmt.Println("用户id不存在")
}
} else {
fmt.Println("输入错误")
}
}
方法二:
//main.go
package main
import (
"flag"
"fmt"
"github.com/strive-after/users/lib"
"os"
)
func main() {
var (
user string
menu string
)
path := flag.String("T","json","json or gob")
help := flag.Bool("h",false,"help")
flag.Usage = func() {
fmt.Println("-T [json/gob]")
}
flag.Parse()
if *help {
flag.Usage()
flag.PrintDefaults()
os.Exit(0)
}
lib.GetPeristence(*path)
if !lib.Auth() {
fmt.Println("您输入的密码错误,系统退出")
return
}
for {
//界面打印
menu = `====================
欢迎使用用户管理系统
====================
1.添加用户
2.查找用户
3.修改用户
4.删除用户
5.修改密码
6.退出程序
====================`
fmt.Println(menu)
//用户选择
user = lib.Inputstring("请输入指令:")
fmt.Println("====================")
if user == "1" {
lib.Add(lib.GetId())
} else if user == "2" {
lib.Sel()
} else if user == "3" {
lib.Change()
} else if user == "4" {
lib.Del()
} else if user == "5" {
lib.SetPassword()
}else if user == "6"{
break
} else {
fmt.Println("输入有误请重新输入")
continue
}
}
}
package lib
import (
“encoding/gob”
“encoding/json”
“fmt”
“os”
“path/filepath”
“sort”
“strconv”
“time”
)
//load&save.go
//存储用户信息
type Users map[int]User
type JsonPath struct {
name string
}
type GobPath struct {
name string
}
type Persistence interface {
LoadUser() (map[int]User)
SaveUser(map[int]User)
NewPath() string
}
var Persi Persistence
func GetPeristence(name string) {
switch name {
case "gob" :
Persi = GobPath{"user.gob"}
case "json":
Persi = JsonPath{"user.json"}
default:
Persi = JsonPath{"user.json"}
}
}
func (jsonPath JsonPath) NewPath() string {
jsonPath.name = "user.json"
return jsonPath.name
}
func (gobpath GobPath) NewPath() string {
gobpath.name = "user.gob"
return gobpath.name
}
func (jsonpath JsonPath)SaveUser(UserInfo map[int]User) {
//对文件重命名 加时间后缀
if _,err := os.Stat(Persi.NewPath()); err == nil{
os.Rename(Persi.NewPath(),strconv.FormatInt(time.Now().Unix(),10)+Persi.NewPath())
}
//删除文件 保留3个最新的
if filebak,err := filepath.Glob("*.user.gob");err == nil{
// //默认是升序 我们要保留最新的 就用倒叙的方式排序 删除3个以后的ok
sort.Sort(sort.Reverse(sort.StringSlice(filebak)))
//fmt.Println(filebak)
if len(filebak) >= 3 {
for _,v := range filebak[3:]{
os.Remove(v)
}
}
}
if file,err := os.Create(Persi.NewPath());err == nil {
defer file.Close()
encode := json.NewEncoder(file)
encode.SetIndent("","\t")
encode.Encode(UserInfo)
}
}
//加载用户信息
func (jsonpath JsonPath) LoadUser() (map[int]User) {
UserInfo := map[int]User{}
//判断文件是否存在
if file,err := os.Open(Persi.NewPath());err == nil {
defer file.Close()
//创建解码器
decode := json.NewDecoder(file)
//将流中的数据编码到对象中 这里UserInfo 是对象 要取指针
decode.Decode(&UserInfo)
}else { //这里err != nil
if !os.IsNotExist(err) { //如果不是因为文件不存在 打印报错
fmt.Printf("[-]发生错误%v",err)
}
}
return UserInfo
}
func (gobpath GobPath)SaveUser(UserInfo map[int]User) {
//对文件重命名 加时间后缀
if _,err := os.Stat(Persi.NewPath()); err == nil{
// //os.Rename(userpath,fmt.Sprintf("%x",time.Now())+".user.csv")
os.Rename(Persi.NewPath(),strconv.FormatInt(time.Now().Unix(),10)+".user.gob")
}
//删除文件 保留3个最新的
if filebak,err := filepath.Glob("*.user.gob");err == nil{
// //默认是升序 我们要保留最新的 就用倒叙的方式排序 删除3个以后的ok
sort.Sort(sort.Reverse(sort.StringSlice(filebak)))
//fmt.Println(filebak)
if len(filebak) >= 3 {
for _,v := range filebak[3:]{
os.Remove(v)
}
}
}
if file,err := os.Create(Persi.NewPath());err == nil {
defer file.Close()
encode := gob.NewEncoder(file)
encode.Encode(UserInfo)
}
}
//加载用户信息
func (gopath GobPath) LoadUser() map[int]User {
UserInfo := map[int]User{}
//判断文件是否存在
if file,err := os.Open(Persi.NewPath());err == nil {
defer file.Close()
//创建解码器
decode := gob.NewDecoder(file)
//将流中的数据编码到对象中 这里UserInfo 是对象 要取指针
decode.Decode(&UserInfo)
}else { //这里err != nil
if !os.IsNotExist(err) { //如果不是因为文件不存在 打印报错
fmt.Printf("[-]发生错误%v",err)
}
}
return UserInfo
}
//import.go
package lib
import (
"bufio"
"fmt"
"os"
"strings"
"time"
)
//因为需要用户输入的比较多定义一个input函数
func Inputstring(input string) string {
//这里使用带缓冲的io
//创建scanner
scanner := bufio.NewScanner(os.Stdin)
fmt.Printf(input)
//获取用户信息
scanner.Scan()
//返回读取的行信息 text每次读一行
return strings.TrimSpace(scanner.Text())
}
func Inputuser(id int) {
UserInfo := Persi.LoadUser()
var user User
var err error
START:
user.ID = id
user.Name = Inputstring("请输入名字:")
user.Birthday,err = time.Parse("2006-1-2",Inputstring("请输入生日(如2006-1-2):"))
user.Tel = Inputstring("请输入联系方式:")
user.Addr = Inputstring("请输入住址:")
user.Desc = Inputstring("请输入备注:")
if err == nil {
for k,v := range UserInfo {
if k == id {
break
}else if v.Name == user.Name {
fmt.Println("用户已存在,请重新输入")
fmt.Println(strings.Repeat("-", 20))
goto START
}else if user.Name == ""{
fmt.Println("用户名不能为空,请重新输入")
goto START
}
}
UserInfo[id] = user
Persi.SaveUser(UserInfo)
}else {
fmt.Println("格式有误,请重新输入")
goto START
}
}
//auth.go
package lib
import (
"crypto/md5"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/howeyc/gopass"
)
//定义密码输入次数
//定义用户结构体
type User struct {
ID int
Name string
Birthday time.Time
Tel string
Addr string
Desc string
}
const (
passwordFile = "./passworld"
maxauth = 3
)
func GetId() int {
var id int
UserInfo := Persi.LoadUser()
for k,_ := range UserInfo {
if id < k {
id = k
}
}
return id + 1
}
//使用系统前输入密码 超过3次则退出系统
func Auth() bool {
//password, err := os.Open(passwordFile)
password ,err := ioutil.ReadFile(passwordFile)
//打开密码文件如果err!=nil 就是说打开有问题
if err != nil || len(password) < 1 {
//如果是因为不存在 那么我们需要初始化密码
if os.IsNotExist(err) || len(password) < 1 {
fmt.Print("请输入初始化密码:")
bytes, _ := gopass.GetPasswd()
//将用户输入的密码md5加密 写入文件
ioutil.WriteFile(passwordFile, []byte(fmt.Sprintf("%x",md5.Sum(bytes))), 0644)
return true
} else { //如果不是因为不存在 那么打印报错信息
fmt.Println(err)
}
} else { //如果存在 那么就需要做密码验证
//defer password.Close()
for i := 1; i <= maxauth; i++ {
// user := Inputstring("请输入密码:")
fmt.Printf("请输入密码:")
bytes, _ := gopass.GetPasswd()
//这里对输入的密码进行md5加密并且与常量比较
//%x是小写十六进制表示 Sprintf格式化返回一个字符串
passwd ,_:= ioutil.ReadFile(passwordFile)
if fmt.Sprintf("%x", md5.Sum(bytes)) == string(passwd) {
return true
} else {
fmt.Printf("输入错误请重新输入,您还有%d次机会\n", maxauth-i)
}
}
return false
}
return false
}
func SetPassword() {
fmt.Printf("请输入旧密码:")
bytes, _ := gopass.GetPasswd()
if passwd ,_:= ioutil.ReadFile(passwordFile);string(passwd) == fmt.Sprintf("%x",md5.Sum(bytes)){
fmt.Print("请输入新密码")
bytes, _ := gopass.GetPasswd()
ioutil.WriteFile(passwordFile, []byte(fmt.Sprintf("%x",md5.Sum(bytes))), 0644)
fmt.Println("密码修改成功")
}else {
fmt.Println("密码输入错误")
}
}
//add.go
package lib
import "fmt"
//添加用户
func Add(id int) {
Inputuser(id)
fmt.Println("[+]添加成功")
}
//修改用户
//change.go
package lib
import (
"fmt"
"strconv"
"strings"
)
func Change() {
UserInfo := Persi.LoadUser()
if id, err := strconv.Atoi(Inputstring("请输入修改的用户id:")); err == nil {
fmt.Println(strings.Repeat("-", 20))
if user, ok := UserInfo[id]; ok {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n",user.ID, user.Name,user.Birthday.Format("2006-1-2"),user.Tel,user.Addr,user.Desc)
fmt.Println(strings.Repeat("-", 20))
affirm := Inputstring("确认是否修改(Y/N):")
if affirm == "Y" || affirm == "y" {
Inputuser(id)
}
} else {
fmt.Println("用户id不存在")
}
} else {
fmt.Println("输入错误")
}
}
//查询用户
//sel.go
package lib
import (
"fmt"
"sort"
"strings"
)
func Sel() {
UserInfo := Persi.LoadUser()
user := Inputstring("请输入要查询的信息:")
list := make([]User,0)
fmt.Println(strings.Repeat("-", 20))
for _, v := range UserInfo {
if strings.Contains(v.Name, user) || strings.Contains(v.Desc, user) || strings.Contains(v.Addr, user) || strings.Contains(v.Tel, user) || strings.Contains(v.Birthday.Format("2006-01-02"), user) {
list = append(list,v)
}
}
users := Inputstring("请输入要排序的属性(ID,Name,Desc,Addr,Tel,Birthday):")
sort.Slice(list, func(i, j int) bool {
switch users {
case "ID":
return list[i].ID < list[j].ID
case "Name":
return list[i].Name < list[j].Name
case "Desc":
return list[i].Desc < list[j].Desc
case "Addr":
return list[i].Addr < list[j].Addr
case "Tel":
return list[i].Tel < list[j].Tel
case "Birthday":
return list[i].Birthday.Format("2006-1-2") < list[j].Birthday.Format("2006-1-2")
default:
return list[i].ID < list[j].ID
}
})
for _,v := range list {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n", v.ID,v.Name,v.Birthday.Format("2006-1-2"),v.Tel,v.Addr,v.Desc)
fmt.Println(strings.Repeat("-", 20))
}
}
//删除用户
//del.go
package lib
import (
"fmt"
"strconv"
"strings"
)
func Del() {
UserInfo := Persi.LoadUser()
if id, err := strconv.Atoi(Inputstring("请输入删除的用户id:")); err == nil {
fmt.Println(strings.Repeat("-", 20))
if user, ok := UserInfo[id]; ok {
fmt.Printf("ID:%d\nname:%s\nbirthday:%v\ntel:%s\naddr:%s\ndesc:%s\n",user.ID ,user.Name,user.Birthday.Format("2006-1-2"),user.Tel,user.Addr,user.Desc)
fmt.Println(strings.Repeat("-", 20))
affirm := Inputstring("确认是否删除(Y/N):")
if affirm == "Y" || affirm == "y" {
delete(UserInfo, id)
Persi.SaveUser(UserInfo)
fmt.Println("[-]删除成功")
}
} else {
fmt.Println("用户id不存在")
}
} else {
fmt.Println("输入错误")
}
}
推荐阅读