通过实现一个简单的K–V存储数据库,学习Go语言(三)
作为数据库我们需要将键值存储的数据保存在磁盘上,以及如何在下一次启动应用程序时将其加载到内存。
我们准备创建两个新函数,
save()
保存数据到磁盘,load()
从磁盘加载数据。将数据转换为字节流的过程称为序列化。读取数据文件并将其转换为对象的过程称为反序列化。
encoding/gob
标准
Go包将用于程序中。它将有助于序列化和反序列化过程。
encoding/gob
包使用gob
格式存储其数据。这种格式的官方名称是流编码。
gob
格式的好处是,Go
完成了所有的繁琐工作,因此你不必担心编码和解码阶段。
package main
import (
"bufio"
"encoding/gob"
"fmt"
"os"
"strings"
)
var DATA = map[string]string{}
var DATAFILE = "dataFile.gob"
//myRedis基础功能
func SET(key string, value string) {
if _, ok := DATA[key]; !ok {
DATA[key] = value
//fmt.Println("set successful!")
} else {
fmt.Println("error: existence of this key!")
}
}
func GET(key string) {
if _, ok := DATA[key]; !ok {
fmt.Println("error: not found this key!")
} else {
fmt.Printf("%s\n", DATA[key])
}
}
func DELETE(key string) {
if _, ok := DATA[key]; !ok {
fmt.Println("error: not found this key!")
} else {
delete(DATA, key)
//fmt.Println("delete successful!")
}
}
func UPDATE(key string, value string) {
if _, ok := DATA[key]; !ok {
fmt.Println("error: not found this key!")
} else {
DATA[key] = value
//fmt.Println("update successful!")
}
}
func SHOW() {
for k, v := range DATA {
fmt.Printf("%s:%s\n", k, v)
}
}
//数据持久化
//保存数据在磁盘上
func save() error {
//去除原数据文件,保存为新数据文件
err := os.Remove(DATAFILE)
if err != nil {
fmt.Println(err)
}
saveFile, err := os.Create(DATAFILE)
if err != nil {
fmt.Println("Cannot create", DATAFILE)
return err
}
defer saveFile.Close()
//序列化存储数据到文件
encoder := gob.NewEncoder(saveFile)
//转码数据
err = encoder.Encode(DATA)
fmt.Println(DATA, saveFile, DATAFILE)
if err != nil {
fmt.Println("Cannot save to", DATAFILE)
return err
}
return nil
}
//启动应用时,加载数据
func load() error {
loadFile, err := os.Open(DATAFILE)
defer loadFile.Close()
if err != nil {
fmt.Println("Empty key/value store!")
return err
}
//反序列化读取文件
decoder := gob.NewDecoder(loadFile)
//解码数据
decoder.Decode(&DATA)
return nil
}
func main() {
//load File
err := load()
if err != nil {
fmt.Println(err)
}
cmd := []string{}
s := bufio.NewScanner(os.Stdin)
for s.Scan() {
text := s.Text()
cmd = strings.Split(text, " ")
//strings.TrimSpace()
//strings.Fields()
switch cmd[0] {
case "SET":
SET(cmd[1], cmd[2])
case "GET":
GET(cmd[1])
case "SHOW":
SHOW()
case "DELETE":
DELETE(cmd[1])
case "UPDATE":
UPDATE(cmd[1], cmd[2])
case "STOP":
err = save()
if err != nil {
fmt.Println(err)
}
default:
fmt.Println("Unknown command - please try again!")
}
}
//end to save file
err = save()
if err != nil {
fmt.Println(err)
}
}