Go练习题(8-1)

V1 使用函数来解决需求

需求(在之前的用户管理的基础上)
1.用户数据持久化 gob csv 密码也持久化 每次操作完持久化 User不能有全局的 每次需要用User 从文件反序列化
2.当文件不存在,获取反序列化失败,不能报错
3.密码文件不存在 让用户初始化密码

3.保存文件 加一个版本 数据文件每次保存一个版本 最多保留3个版本

4.修改密码(输入原密码和新密码 只有在原密码正确的时候 新密码持久化)

1.CSV
在这里插入图片描述

//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&cave.go
//持久化
package lib

import (
	"encoding/csv"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"time"
)

const userpath string = "./user.csv"
//存储用户信息


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.csv")
	}
	//删除文件 保留3个最新的
	if filebak,err := filepath.Glob("*.user.csv");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)
			}
		}
	}
	file,err := os.Create(userpath)
	if err == nil {
		defer file.Close()
		writer := csv.NewWriter(file)
		for _,users := range UserInfo{
			writer.Write([]string{
				strconv.Itoa(users.ID),
				users.Name,
				users.Birthday.Format("2006-1-2"),
				users.Tel,
				users.Addr,
				users.Desc,
			})
			writer.Flush()
		}
	}

}

//加载用户信息
func LoadUser()map[int]User {
	UserInfo := map[int]User{}
	//判断文件是否存在
	if file,err := os.Open(userpath);err == nil {
		defer  file.Close()
		reader := csv.NewReader(file)
		for {
			//这里line 每次读取一行  是[]string类型
			line,err := reader.Read()
			if err != nil {
				if err != io.EOF {
					fmt.Printf("[-]错误:%v",err)
				}
				break
			}else {
				id ,_:= strconv.Atoi(line[0])
				bir,_ := time.Parse("2006-1-2",line[2])
				UserInfo[id]  = User{
					ID:       id,
					Name:     line[1],
					Birthday: bir,
					Tel:      line[3],
					Addr:     line[4],
					Desc:     line[5],
				}
			}
		}

	}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
	Name  string
	Birthday time.Time
	Tel string
	Addr string
	Desc string
}


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("[+]添加成功")
}
//查询用户
//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(string(v.ID), user)||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))
	}


}
//修改用户
//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("输入错误")
	}
}
//删除用户
//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("输入错误")
	}
}

2.GOB
在这里插入图片描述

//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/gob"
	"fmt"
	"os"
	"path/filepath"
	"sort"
	"strconv"
	"time"
)

const userpath string = "./user.gob"
//存储用户信息


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.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(userpath);err == nil {
		defer file.Close()
		encode := gob.NewEncoder(file)
		encode.Encode(UserInfo)
	}
}

//加载用户信息
func   LoadUser() map[int]User {
	UserInfo := map[int]User{}
	//判断文件是否存在
	if file,err := os.Open(userpath);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
}
//imput.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
	}
}
//add.go
package lib

import "fmt"

//添加用户
func Add(id int) {
	Inputuser(id)
	fmt.Println("[+]添加成功")
}
//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 := 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("密码输入错误")
	}
}
//修改用户

//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("输入错误")
	}
}
//删除用户
//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("输入错误")
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章