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